IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 力扣每日一题----求第n位斐波那契数 -> 正文阅读

[数据结构与算法]力扣每日一题----求第n位斐波那契数

题目解析

方法一 暴力递归求解

这种方法其实就是使用递归的思想来求解,将每个数看成是一颗二叉树的节点,当且仅当找到二叉树的叶子节点(两个初始值0和1)时才结束循环,也就是递归的终止条件。画图说明,如下:
在这里插入图片描述
可以看出计算第n个节点的斐波那契数,即需要计算出整个二叉树每个节点的值,时间复杂度为2的n次方,非常庞大,代码见下。

方法二 暴力递归的优化

暴力递归求解中的时间复杂度如何去降低呢?可以发现,暴力递归需要计算上图中的每个二叉数节点的值,但是其中有一些值的计算是可以去除的,就是说存在大量的节点值的计算是冗余的。不难看出,当计算根节点时,需要计算节点4和节点3的值,但是计算节点4的值又需要计算节点3和节点2的值,如果左子树的值计算完毕,那么右子树的值就不要再去递归求解了,因此只需要计算图中的最长一条路径左中的节点的值,根节点的值自然可以求出。如下图,只需要计算红色路径上的值即可:
在这里插入图片描述

依次思路,只需要计算n个斐波那契数,时间复杂度可降低为O(n);
但是如何去得到每个节点的值呢?需要使用一个数组,来保存每次计算的节点值,最多只有n个值,那么空间复杂度为O(n)。

方法三 双指针思想

虽然方法二中去重递归可以将时间复杂度降低为O(n), 但是空间复杂度也为O(n),如何去降低这个空间复杂度呢?逐步求解某一个位置的元素值,并且是由某两个值来得到的,类似这种问题,都可以联想到双指针思想:
慢指针指向数组最左端,快指针指向数组下标为1的位置,逐步更新两个指针所指向的元素,直至遍历到第n个元素为止,即可得到第n个斐波那契数,此时的时间复杂度不变还是O(n),而空间上只有两个指针,并没有使用额外的空间,因此空间复杂度为O(1)。

代码解析

1. 暴力递归

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

2. 去重递归

    public static int Fib2(int num) {
        int[] arr = new int[num + 1]; //初始化全为0的整型数组,用来保存每次计算得到的Fib数值,避免重复计算
        return resurse(arr, num);
    }

    private static int resurse(int[] arr, int nums) {
        if (nums == 0) {
            return 0;
        }
        if (nums == 1) {
            return 1;
        }
        if (arr[nums] != 0) { //如果该Fib数不为0表示之前已经计算过该值了,直接进行返回,对于第一次才计算的值才使用递归求解
            return arr[nums];
        }
        arr[nums] = resurse(arr, nums - 1) + resurse(arr, nums - 2);
        return arr[nums];
    }

注意:这里的arr数组初始化为全0的整数数组,因为后面当第一次计算某个斐波那契数时才需要进行递归求解,否则,当某个斐波那契数被计算得到了,此时已经存在数组arr的某个位置处,这个元素就不再是0了。当下一次再使用该值时,就不要再一次进行计算,直接返回该值即可。

3. 双指针求解

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

定义两个指针:慢指针指向数组下标0,快指针指向数组下标1,同上设定两个default也就是两个斐波那契的初始值。从下标位置2开始循环,将上一次的元素进行加和得到当前的斐波那契数sum,更新两个指针:快指针所指向的值赋值给慢指针low,当前得到的斐波那契数sum赋值给快指针high,进行下一次求解,直至循环到第num个元素结束。最后直接返回快指针high即可,low指针保存的是上一个斐波那契数。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:34:33  更:2021-08-08 11:51:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:48:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码