【今日面试题】设计一个程序比较常规递归与记忆化递归的区别

【今日面试题】设计一个斐波拉契数列程序比较常规递归与记忆化递归的区别

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");
    }
}

java版本运行结果示例

在这个程序中,我们使用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;
}

c++版本运行结果

这个程序会让用户输入一个数字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详细参考这篇文章

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值