Обрезка последовательности Фибоначчи с использованием Java

Вот моя реализация последовательности Фибоначчи с использованием Java

/**
 * Returns nth fibonacci number
 */
public class fib {

   public static void main(String[] args){
      System.out.println(fibonacci(12));
   }

   public static int fibonacci(int n) {
      if (n == 0){
         return 0;
      } else if (n == 1){
         return 1;
      } else {
         return fibonacci(n - 1) + fibonacci(n - 2);
      }
   }
}

Но визуализация этого метода с использованием рекурсии заставила меня думать, что это будет намного быстрее. Вот визуализация fib (5). https://imgur.com/a/2Rgxs Но это заставило меня задуматься. Обратите внимание, что когда мы поднимаемся вверх от нижней части рекурсивного пути, мы вычисляем fib(2), fib(3) и fib(4), но затем мы пересчитаем fib (3) в самой верхней правой ветви. Поэтому я подумал, когда мы снова всплываем, почему бы не сохранить fib (3), вычисленный по левой ветви, чтобы мы не делали никаких вычислений по правой ветви, как мой метод в настоящее время делает, как хеш-таблица при возврате. У меня вопрос, как мне реализовать эту идею?

3 ответа

Когда вы хотите добавить HashMap и оставайтесь со своим оригинальным подходом, попробуйте это:

static HashMap<Integer, Integer> values = new HashMap<Integer, Integer>();

public static void main(String[] args){
    values.put(0, 0);
    values.put(1, 1);
    System.out.println(fibonacci(12));
}

public static int fibonacci(int n) {
    if (values.containsKey(n)){
        return values.get(n);
    } else {
        int left = values.containsKey(n - 1) ? values.get(n - 1) : fibonacci(n - 1);
        values.put(n - 1, left);
        int right = values.containsKey(n - 2) ? values.get(n - 2) : fibonacci(n - 2);
        values.put(n - 2, right);
        return left + right;
    }
}

Этот подход может быть очень быстрым, если вы вызываете его чаще, потому что результаты Фибоначчи уже сохранены в values (наверняка это можно сделать и с другими подходами):

public static void main(String[] args){
    values.put(0, 0);
    values.put(1, 1);
    System.out.println(fibonacci(12));
    System.out.println(fibonacci(11));
    System.out.println(fibonacci(10));
}

Для быстрого расчета вам вообще не нужна рекурсия - достаточно сдвинуть промежуточные результаты

public static int fibonacci(int n) {
  if (n == 0) {
  return 0;
  } else {
    int npp = 0; // pre-previous number
    int np = 1; // previouse number
    int r = 1; // current number, eventually the result
    for (int i = 2; i <= n; i++) {
      r = np + npp;
      npp = np;
      np = r;
    }

    return r;
  }
}

Чтобы избежать повторных расчетов, вы можете использовать динамическое программирование. Кстати, это не оптимизированное для памяти решение, но оно может быть быстрее рекурсивного.

public static int fibonacci(int n)
{    
    int f[] = new int[n+1];

    for (int i = 0; i <= n; i++) {
        if(i == 0 || i == 1) {
            f[i] = i;
        }
        else {
            f[i] = f[i-1] + f[i-2];
        }
    }

    return f[n];
}
Другие вопросы по тегам