深入浅出总结求解菲波那切数列的五种方法

article/2025/8/30 2:38:03

文章目录

  • 题目
  • 思路一: 递归
  • 思路二: 递归 + 剪枝 (递归的优化)
  • 思路三: 动态规划
  • 思路四: 迭代 (动态规划的优化)
  • 思路五: 矩阵运算 + 快速幂

题目

菲波那切数列

定义 a0 = 0, a1 = 1, a2 = 1, an = an − 1 + an − 2, 求 an 是多少?

思路一: 递归

        由于每一项都遵循这个公式: an = an − 1 + an − 2, 所以就直接递归来实现(普通的递归不需要多讲, 相信你们之前都已经做过了).

代码:

public class Solution {public int Fibonacci(int n) {if(n == 0 || n == 1){return n;}return Fibonacci(n - 1) + Fibonacci(n - 2);}
}

思路二: 递归 + 剪枝 (递归的优化)

        对于上面的普通递归, 会一直在进行深度遍历, 直到 0 或者 1 的时候, 才会返回, 这样的话就会涉及到很多重复计算(非常容易就栈溢出了). 对此我们可以对其进行一下优化: 剪枝.
        在这道题中, 我们可以使用哈希表来将每一次计算得到的值存储在哈希表当中, 当下一次需要再计算到这个位置的时候, 就可以直接在哈希表上查找即可, 不需要再继续往下进行深度遍历, 从而达到剪枝的效果.

import java.util.*;public class Solution {private Map<Integer, Integer> map = new HashMap<>();public int Fibonacci(int n) {if(n == 0 || n == 1){return n;}if(n == 2){return 1;}int ppre = 0;if(map.containsKey(n - 2)){ppre = map.get(n - 2);}else{ppre = Fibonacci(n - 2);map.put(n - 2, ppre);}int pre = 0;if(map.containsKey(n - 1)){pre = map.get(n - 1);}else{pre = Fibonacci(n - 1);map.put(n - 1, pre);}return pre + ppre;}
}

思路三: 动态规划

        在这道题中, 我们很简单地就可以找出状态转移方程: q[i] = q[i - 1] + q[i - 2]. 所以直接写即可.

public class Solution {public int Fibonacci(int n) {int[] q = new int[n + 1];q[0] = 0;q[1] = 1;for(int i = 2; i <= n; i++){q[i] = q[i - 1] + q[i - 2];}return q[n];}
}

思路四: 迭代 (动态规划的优化)

        由于上面动态规划的做法是需要开辟一个额外的数组来存储每一个位置上的值, 其实我们可以对其进行一下优化, 那就是不要开辟空间来存储这些值, 直接让这些值来内部自己反复迭代计算, 直到最后的那个值就是目标值.

public class Solution {public int Fibonacci(int n) {if(n == 0){return 0;}int first = 1;int second = 1;int third = 1;while(n-- > 2){third = first + second;first = second;second = third;}return third;}
}

思路五: 矩阵运算 + 快速幂

        这种思路是非常巧妙的, 可以将时间复杂度降到 O(logn).

在这里插入图片描述
        通过这个矩阵运算, 我们就可以将f(n - 1) 和 f(n - 2) 转化成 f(n) 和 f(n - 1). 我们就可以得出一个结论: 每次我们乘上这样的一个矩阵之后, 这些元素就会向后走一步, 那么我们要求第n步之后的结果, 由于我们已经知道了第一步, 那么就只需要区这个矩阵的n - 1次方即可. 因为这里设计到了幂运算, 所以我们就可以很自然地就想到使用快速幂的方法(这种做法推荐有一定算法基础的看看, 了解即可).

public class Solution {public int Fibonacci(int n) {if(n == 0 || n == 1){return n;}//矩阵快速幂运算long[][] t = {{1, 1},{1, 0}};long[][] res = {{1, 0},{0, 0}};int count =  n - 1;while(count > 0) {if((count & 1) == 1) res = mul(res, t); // 注意矩阵乘法顺序,不满足交换律t = mul(t, t);count >>= 1; }return (int)(res[0][0]);}//两矩阵相乘运算public long[][] mul(long[][] a, long[][] b) {// 矩阵乘法,新矩阵的行数 = a的行数rowa,列数 = b的列数colb// a矩阵的列数 = b矩阵的行数 = commonint row = a.length, col = b[0].length, common = b.length;long[][] res = new long[row][col];for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {for (int k = 0; k < common; k++) {res[i][j] += a[i][k] * b[k][j];}}}return res;}
}

        对于初学者来说, 矩阵快速幂还是有一定难度的, 到后面慢慢学过了之后就不是很难的, 之后代码熟练了之后, 这个矩阵快速幂算法的模板也是要背下来的.


http://chatgpt.dhexx.cn/article/3pXCBVO0.shtml

相关文章

图解寻址方式

注: 学习自 唐朔飞《计算机组成原理》 图自 唐朔飞《计算机组成原理》PPT整合 寻址方式 一丶指令寻址 二丶数据寻址 堆栈寻址

寻址方式一

目录 立即数、寄存器、存储器的概念 数据寻址方式 立即寻址&#xff1a; 寄存器寻址&#xff1a; 存储器寻址: 注意&#xff1a; 立即数、寄存器、存储器的概念 立即数&#xff1a;参与操作的数据本身&#xff0c;8位或16位 &#xff08;只能作为src,无法成为dst&#xf…

计算机寻址方式

一、指令寻址 1.两种方式 顺序寻址 每次寻址后 PC自动 1 &#xff1b; 跳跃寻址 当跳转到 JUP 指令时 其后的为立即数指令 &#xff0c;便跳转到对应的指令数。 数据寻址 立即寻址特征 地址村的为立即数特征 直接寻址特征 形式地址为&#xff1a; 操作数的真实地址 隐含寻…

指令格式与寻址方式

指令与指令系统 指令: 控制计算机完成某种操作的命令。 指令系统&#xff1a; 处理器所能识别的所有指令的集合。 指令的兼容性&#xff1a; 同一系列机的指令都是兼容的。 汇编语言&#xff1a; 指令助记符。 指令格式 例如&#xff1a; 寻址方式 操作数可能的来源或…

寻址方式介绍

根据指令内容确定操作数地址的过程称为寻址。完善的寻址方式可为用户组织和使用数据提供方便。 ①直接寻址&#xff1a;指令地址域中表示的是操作数地址。 ②间接寻址&#xff1a;指令地址域中表示的是操作数地址的地址即指令地址码对应的存储单元所给出的是地址A&#xff0c…

8086寻址方式

8086寻址方式 寻址方式总共有两大类: 按数据寻址 按地址寻址 1.数据寻址方式 MOV DST,SRC和数据有关的寻址方式 1.立即寻址: 操作数直接在源操作数中给出 MOV AL,45H 源操作数在指令中给出,立即数只能是源操作数 立即数的长度和DST长度一致 2.寄存器寻址 操作数放在指定的寄存…

数据寻址方式

以下例子中的寻址方式说的都是源操作数&#xff0c;因为目的操作数都用的是寄存器寻址&#xff0c;不再讨论 1.立即寻址 立即寻址是指令直接给出立即数本身作为操作数&#xff0c;立即数作为指令的一部分跟指令一起存在于代码段中&#xff0c;会被指令预取队列直接取到CPU中进…

IPv6 寻址方式简介

在计算机网络中&#xff0c;寻址模式是指在网络上托管地址的机制。IPv6 提供了多种类型的模式&#xff0c;可以通过这些模式对单个主机进行寻址。也可以同时对多个主机进行寻址或者寻址最近距离的主机。 单播寻址 在单播寻址方式中&#xff0c;IPv6 接口&#xff08;主机&…

七种寻址方式(立即寻址、寄存器寻址)

七种寻址方式(立即寻址、寄存器寻址) 一、立即寻址方式 操作数作为指令的一部分而直接写在指令中&#xff0c;这种操作数称为立即数&#xff0c;这种寻址方式也就称为立即数寻址方式。 立即数可以是8位、16位或32位&#xff0c;该数值紧跟在操作码之后。如果立即数为16位或32位…

8086寻址方式图解

目录 1&#xff1a;立即寻址 2&#xff1a;寄存器寻址 3&#xff1a;直接寻址&#xff08;存储器直接寻址&#xff09; 4&#xff1a;寄存器间接寻址&#xff08;重点&#xff09; 5&#xff1a;基址寻址&#xff08;相对寻址&#xff09; 6&#xff1a;变址寻址 &#x…

七种寻址方式

七种寻址方式&#xff08;从该处学习转载&#xff0c;感谢&#xff0c;如有侵犯&#xff0c;请联系删除&#xff09; 立即寻址 操作数作为指令的一部分而直接写在指令中&#xff0c;这种操作数称为立即数&#xff0c;这种寻址方式也就称为立即数寻址方式。 立即数寻址方式通…

十种寻址方式

寻址方式 寻址方式分为指令寻址和数据寻址。 目录 寻址方式 一、指令寻址 二、数据寻址 1.立即寻址 2.直接寻址 3.隐含寻址 4.间接寻址 5.寄存器&#xff08;直接&#xff09;寻址 6.寄存器间接寻址 7.基址寻址 8.变址寻址 9、相对寻址 10、堆栈寻址 一、指令寻…

常用的图像特征提取方法

1. 灰度特征可提取&#xff1a;灰度平均值、方差 2.纹理特征提取 MATLAB程序&#xff1a; %%%特征提取 clear all; close all; clc;Ddir(E:\my_work\长光所\云图\数据集\云样本\*.jpg); cloud_featurezeros(length(D),5);for i1:length(D)imgimread([E:\my_work\长光所\云图\…

OpenCV图像特征提取

Camera系列文章 传感器融合是将多个传感器采集的数据进行融合处理&#xff0c;以更好感知周围环境&#xff1b;这里首先介绍Camera的相关内容&#xff0c;包括摄像头及图像知识基本介绍&#xff0c;OpenCV图像识别&#xff08;特征提取&#xff0c;目标分类等&#xff09;&…

(八)特征选择与特征提取

特征选择与特征提取 一、特征的选择 1、原始特征 在描述对象的时候 模式识别中把每个对象都量化为一组特征来描述&#xff0c;构建特征空间是解决模式识别问题的第一步&#xff0c;其中通过直接测量得到的特征称为原始特征。 如&#xff1a; - 人体的各种生理指标&#xff0…

机器学习之特征提取

机器学习之特征提取 1.为什么要特征提取 原始数据常常是高维的&#xff0c;其中包含了许多冗余信息或者十分稀疏或者计算量大&#xff0c;拿原始数据来训练可行&#xff0c;但是往往直接训练是低效的。所以特征提取往往是必要的。 注&#xff1a;特征提取主要是为了解决下面三…

【机器学习】特征提取

特征提取 目标 应用DictVectorizer实现对类别特征进行数值化、离散化 应用CountVectorizer实现对文本特征进行数值化 应用TfidfVectorizer实现对文本特征进行数值化 说出两种文本特征提取的方式区别 定义 特征提取是将任意数据&#xff08;如文本或图像&#xff09;转换…

特征选择与特征抽取

特征抽取和特征选择是DimensionalityReduction&#xff08;降维&#xff09;两种方法&#xff0c;但是这两个有相同点&#xff0c;也有不同点之处&#xff1a; 1. 概念&#xff1a; 特征抽取&#xff08;Feature Extraction&#xff09;:Creatting a subset of new features by…

【特征提取】基于深度学习的特征提取和匹配方法介绍

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达本文转自 | AI深度学习视线精彩内容 计算机视觉需要图像预处理&#xff0c;比如特征提取&#xff0c;包括特征点&#xff0c;边缘和轮廓之类。以前做跟踪和3-D重建&#…

特征工程之特征提取

![ 什么是特征提取呢&#xff1f; 1 特征提取 1 将任意数据&#xff08;如文本或图像&#xff09;转换为可用于机器学习的数字特征 注&#xff1a;特征值化是为了计算机更好的去理解数据 字典特征提取(特征离散化) 文本特征提取 图像特征提取&#xff08;深度学习将介绍&…