【今日面试题】设计一个斐波拉契数列程序比较常规递归与记忆化递归的区别
Java版本
import java.util.Scanner;
public class Fibonacci {
static long[] memo;
static long normalRecursive(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return normalRecursive(n - 1) + normalRecursive(n - 2);
}
static long memoRecursive(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
if (memo[n] != 0) return memo[n];
memo[n] = memoRecursive(n - 1) + memoRecursive(n - 2);
return memo[n];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter a number: ");
int n = scanner.nextInt();
scanner.close();
memo = new long[n + 1];
long startTime = System.nanoTime();
long result1 = normalRecursive(n);
long endTime = System.nanoTime();
long duration1 = (endTime - startTime) / 1000;
System.out.println("Normal Recursive Result: " + result1);
System.out.println("Time taken by Normal Recursive: " + duration1 + " microseconds");
startTime = System.nanoTime();
long result2 = memoRecursive(n);
endTime = System.nanoTime();
long duration2 = (endTime - startTime) / 1000;
System.out.println("Memo Recursive Result: " + result2);
System.out.println("Time taken by Memo Recursive: " + duration2 + " microseconds");
}
}
在这个程序中,我们使用memo
数组来存储斐波那契数列中间结果,以实现记忆化递归。程序会提示用户输入一个数字n
,然后计算第n
个斐波那契数,并输出计算结果以及两种方法的耗时。您可以通过运行这个程序来比较记忆化递归和普通递归的时间效率。
C++版本
要设计一个程序来检验记忆化递归的时间效率更高,并且可以实际看到程序的耗时,您可以使用C++中的chrono
库来测量程序的运行时间。下面是一个简单的示例程序,其中包含了两种解决方案:一种是普通递归,另一种是记忆化递归。程序将比较两种方法的运行时间:
#include <iostream>
#include <vector>
#include <chrono>
using namespace std;
using namespace std::chrono;
vector<vector<int>> memo;
int normalRecursive(int n) {
if (n == 0) return 1;
int res = 0;
for (int i = 0; i < n; i++) {
res += normalRecursive(i);
}
return res;
}
int memoRecursive(int n) {
if (n == 0) return 1;
if (memo[n].size() > 0) return memo[n][0];
int res = 0;
for (int i = 0; i < n; i++) {
res += memoRecursive(i);
}
memo[n].push_back(res);
return res;
}
int main() {
int n;
cout << "Enter a number: ";
cin >> n;
memo.resize(n + 1);
auto start1 = high_resolution_clock::now();
int result1 = normalRecursive(n);
auto stop1 = high_resolution_clock::now();
auto duration1 = duration_cast<microseconds>(stop1 - start1);
cout << "Normal Recursive Result: " << result1 << endl;
cout << "Time taken by Normal Recursive: " << duration1.count() << " microseconds" << endl;
auto start2 = high_resolution_clock::now();
int result2 = memoRecursive(n);
auto stop2 = high_resolution_clock::now();
auto duration2 = duration_cast<microseconds>(stop2 - start2);
cout << "Memo Recursive Result: " << result2 << endl;
cout << "Time taken by Memo Recursive: " << duration2.count() << " microseconds" << endl;
return 0;
}
这个程序会让用户输入一个数字n,并分别使用普通递归和记忆化递归来计算结果,然后输出计算结果和两种方法的耗时。您可以运行这个程序来比较两种方法的效率,看看记忆化递归是否更快。
提问:这个里面的memo数组怎么理解
在这段代码中,memo
数组被用作记忆化递归的辅助数据结构。在memoRecursive
函数中,memo
数组被设计成一个二维vector
,其中memo[n]
存储了状态n
下的中间计算结果。
具体来说,memo[n]
是一个存储整数值的向量,用于存储状态n
下的中间结果。在memoRecursive
函数中,首先检查memo[n]
是否已经有值,如果有值,则直接返回memo[n][0]
,避免重复计算。如果memo[n]
为空,表示之前没有计算过状态n
,则进行递归计算,并将结果存储在memo[n]
中,以便后续直接使用。
通过这种设计,memo
数组可以帮助优化递归计算过程,避免重复计算重复的子问题,从而提高算法的效率。在这个例子中,memo
数组的作用是存储中间结果,以便在需要时进行查找和重用,从而优化递归算法的性能。
可能出现的报错
记得在编译时加上 -std=c++11
或更高版本的标志,以确保chrono
库能够正常使用。您可以将这段代码复制粘贴到C++编译器中运行,
如果出现这种报错mingw32/8.1.0/include/c++/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support must be enabled with the -std=c++11 or -std=gnu++11 compiler options.说明你的编译器没有设置成C++11,如果你是使用Clion详细参考这篇文章