【问题标题】:Making this recursive fibonacci with memoization even faster?让这个带有记忆的递归斐波那契更快?
【发布时间】:2018-09-24 03:17:05
【问题描述】:

有没有办法让这个程序运行得更快?它已经比我尝试制作的 HashMap 版本快,但根据我提交的位置,它在 45 分左右仍然太慢。我可以做任何修改来改进它吗?

import java.util.Scanner;

public class Fibo {
    static long[] cache;
    static long ans;

    public static long fibo(int n) {
        if (n == 0) 
            return 1;
        if (n < 2) 
            ans = 1;
        else
            ans = fibo(n - 1) + fibo(n - 2);
        cache[n - 1] = ans;
        return ans;

    }

    public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            System.out.println("test");
            int num = input.nextInt();
            input.close();
            cache = new long[num];
            long ans = fibo(num);
            System.out.println(ans);
    }
}

【问题讨论】:

  • 您实际上从未在 cache 中执行任何查找,还是我遗漏了什么?
  • Fibo() 只从你的 main 方法调用一次,缓存从未真正使用过

标签: java recursion fibonacci memoization


【解决方案1】:

您可以通过实际使用缓存值来加快速度:

public static long fibo(int n) {
    if (cache[n] > 0) {
        return cache[n];
    }
    ...
    cache[n] = ans; // you are saving at the wrong index
    ...
}

虽然使用记忆化在 O(n) 时“快”,但有一个数学 O(log n) 解决方案超级快。

【讨论】:

  • 为什么 OP 保存到错误的索引? OP 永远不会为n=0 保存,因此保存在n-1 是有效的,并且符合数组仅使用大小num 创建的事实。
  • @Andreas 因为它更清晰、更明显并且符合将值保存在cache[parameter] 而不是cache[some other value that may save a whopping 8 bytes of memory] 的一般记忆模式
  • 但是保存在n-1 并不是“错误的”。非标准,也许。也许不太理想。但没有
  • @Andrea 在代码审查时我肯定会说这是错误的,因为它让理解和调试变得更加困难而没有任何收获
【解决方案2】:

您正试图在缓存中记忆答案,但您没有使用它。在进行任何其他计算之前检查您的缓存。此外,当您到达fibo(0) 时,您会得到一个ArrayIndexOutOfBoundsException,因为您要减去一个。删除减法并增加数组的大小以解决它。

public static long fibo(int n) {
    // Try cache first.
    if (cache[n] != 0) return cache[n];
    if (n == 0) 
        return 1;
    if (n < 2) 
        ans = 1;
    else
        ans = fibo(n - 1) + fibo(n - 2);
    // Don't subtract one.
    cache[n] = ans;
    return ans;
}

主要是为fibo(num)的答案腾出空间。

cache = new long[num + 1];

【讨论】:

  • 可能 OP 故意不为n=0 保存,而是保存在n-1,因此只需创建大小为num 的数组。您的代码只会得到ArrayIndexOutOfBoundsException,因为您更改了保存的索引位置。
  • @Andreas 创建我的解决方案时,我首先在方法顶部添加了使用缓存的行。我确实得到了一个 AIOOBE,因为最终fibo(0) 会被调用。因此,在数组中节省一个空间的“减一”是不正确的。另一种方法是在基本情况之后检查缓存。
  • 所以你的错误是你在n==0检查之前添加了缓存检查,并决定以需要更多更改的方式进行修复,而不仅仅是翻支票。
  • @Andreas 我决定以一种更易于理解和可读的方式修复代码。我的目标不是以尽可能少的更改来修复代码,而是以最容易理解、最易读的方式修复代码。对我来说,让数组的索引i 存储fibo(i) 更有意义。
猜你喜欢
  • 2011-12-14
  • 2021-11-17
  • 2019-07-03
  • 1970-01-01
  • 2012-11-29
  • 2010-12-03
  • 2019-06-04
  • 2015-10-19
相关资源
最近更新 更多