常见算法四(斐波那契数列)

目录

暴力递归

记忆化递归

双指针迭代


求取斐波那契数列第N位的值。
斐波那契数列:每一位的值等于他前两位数字之和。前两位固定 0,1,1,2,3,5,8...

斐波那契数列通常定义如下:

  • F(0) = 0
  • F(1) = 1
  • 对于 n > 1,有 F(n) = F(n - 1) + F(n - 2)

暴力递归

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

这个方法的逻辑:

  1. 基本情况

    • 如果 num 等于 0,函数返回 0,因为斐波那契数列的第 0 项是 0。
    • 如果 num 等于 1,函数返回 1,因为斐波那契数列的第 1 项是 1。
  2. 递归情况

    • 如果 num 大于 1,函数递归地调用自身两次,一次是计算 num - 1 的斐波那契数,另一次是计算 num - 2 的斐波那契数,并将这两个值相加得到 num 的斐波那契数。

这种递归方法非常直观,但它的效率并不高。原因在于它进行了大量的重复计算。例如,为了计算 F(5),它将计算 F(4) 和 F(3),但在计算 F(4) 的过程中,它又会计算 F(3) 和 F(2)。这意味着 F(3) 被计算了两次,随着 num 的增大,重复计算的次数会急剧增加。

这个方法的时间复杂度是指数级的,大约是 O(2^n),因为每增加一个 num,计算量大约翻倍。对于较大的 num 值,这个方法将会非常慢。

记忆化递归

使用记忆化递归的方法来计算斐波那契数列的第 num 项的值。

记忆化是一种优化技术,用于提高递归函数处理重复子问题时的效率,是动态规划的一种形式。在这种方法中,将已经计算过的斐波那契数存储在一个数组 arr 中,以避免重复计算。

public static int calculate2 (int num) {
        int[] arr = new int[num + 1];
        return recurse(arr, num);
    }

    public static int recurse (int[] arr, int num) {
        if (num == 0) {
            return 0;
        }
        if (num == 1) {
            return 1;
        }
        if (arr[num] != 0) {
            return arr[num];
        }
        arr[num] = recurse(arr, num -1) + recurse(arr, num -2);
        return arr[num];
    }

这个方法的逻辑:

  1. calculate2 方法初始化一个数组 arr,其长度为 num + 1,用于存储从 0 到 num 的所有斐波那契数。然后它调用 recurse 方法来实际计算斐波那契数。

  2. recurse 方法是一个递归函数,它接受数组 arr 和要计算的斐波那契数的位置 num 作为参数。

  3. 在 recurse 方法中,首先检查基本情况:

    • 如果 num 等于 0,返回 0。
    • 如果 num 等于 1,返回 1。
  4. 如果 arr[num] 不等于 0,这意味着 arr[num] 的值已经被计算过并存储在数组中,直接返回该值,避免了重复计算。

  5. 如果 arr[num] 等于 0,说明我们尚未计算过 num 的斐波那契数。在这种情况下,递归地调用 recurse 来计算 F(num - 1) 和 F(num - 2),将结果相加后存储在 arr[num] 中,并返回该结果。

通过这种方式,每个斐波那契数只计算一次,其余的计算都通过查找数组 arr 来完成,这极大地提高了效率。这个方法的时间复杂度降为 O(n),因为每个数只需要计算一次,并存储在数组中用于后续的查找。

双指针迭代

基于记忆化递归优化,集合没有必要保存每一个下标值,只需保存前两位即可,向后遍历,得出N的值

public static int iterate (int num) {
        if (num == 0) {
            return 0;
        }
        if (num == 1) {
            return 1;
        }
        int low = 0, high = 1;
        for (int i = 2; i <= num; i++) {
            int sum = low + high;
            low = high;
            high = sum;
        }
        return high;
    }

这个迭代方法的逻辑:

  1. 特殊情况处理

    • 如果 num 等于 0,直接返回 0,因为斐波那契数列的第 0 项是 0。
    • 如果 num 等于 1,直接返回 1,因为斐波那契数列的第 1 项是 1。
  2. 初始化两个变量

    • low 被初始化为 0,表示斐波那契数列的第 0 项。
    • high 被初始化为 1,表示斐波那契数列的第 1 项。
  3. 迭代计算

    • 使用一个 for 循环从 2 迭代到 num,在每次迭代中计算当前的斐波那契数。
    • 在循环内部,计算 sum 为 low 和 high 的和,这是当前斐波那契数的值。
    • 然后更新 low 为之前的 high,更新 high 为新计算的 sum
  4. 返回结果

    • 循环结束后,high 存储了斐波那契数列的第 num 项的值,将其返回作为结果。

这种方法只需要两个变量来存储前两个斐波那契数,并通过迭代更新这两个值来计算整个数列,因此它的空间复杂度为 O(1),即它只需要常量级的额外空间。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值