14天阅读挑战赛
努力是为了不平庸~
算法学习有些时候是枯燥的,这一次,让我们先人一步,趣学算法!欢迎记录下你的那些努力时刻(算法学习知识点/算法题解/遇到的算法bug/等等),在分享的同时加深对于算法的理解,同时吸收他人的奇思妙想,一起见证技术er的成长~
不会算法的程序员不是合格程序员,于是我开始学习算法
算法知识点
斐波那契数列
算法题目描述
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
做题思路
方法一:
用递归是会超时的,所以用动态规划。
斐波那契数的边界条件是 F(0)=0F(0)=0 和 F(1)=1F(1)=1。当 n>1n>1 时,每一项的和都等于前两项的和,因此有如下递推关系:
F(n)=F(n-1)+F(n-2)
F(n)=F(n−1)+F(n−2)由于斐波那契数存在递推关系,因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系,边界条件为 F(0)F(0) 和 F(1)F(1)。
根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n)O(n) 的实现。由于 F(n)F(n) 只和 F(n-1)F(n−1) 与 F(n-2)F(n−2) 有关,因此可以使用「滚动数组思想」把空间复杂度优化成 O(1)。计算过程中,答案需要取模 1e9+7。
方法二:矩阵快速幂
方法一的时间复杂度是 O(n)O(n)。使用矩阵快速幂的方法可以降低时间复杂度。
方法一
javascript:
var fib = function(n) { const MOD = 1000000007; if (n < 2) { return n; } let p = 0, q = 0, r = 1; for (let i = 2; i <= n; ++i) { p = q; q = r; r = (p + q) % MOD; } return r; };
java:
class Solution { public int fib(int n) { final int MOD = 1000000007; if (n < 2) { return n; } int p = 0, q = 0, r = 1; for (int i = 2; i <= n; ++i) { p = q; q = r; r = (p + q) % MOD; } return r; } }
C#:
public class Solution { public int Fib(int n) { const int MOD = 1000000007; if (n < 2) { return n; } int p = 0, q = 0, r = 1; for (int i = 2; i <= n; ++i) { p = q; q = r; r = (p + q) % MOD; } return r; } }
动态规划的算法复杂度
时间复杂度:O(n)。
空间复杂度:O(1)。
方法二
js:
var fib = function(n) { if (n < 2) { return n; } const q = [[1, 1], [1, 0]]; const res = pow(q, n - 1); return res[0][0]; }; const pow = (a, n) => { let ret = [[1, 0], [0, 1]]; while (n > 0) { if ((n & 1) === 1) { ret = multiply(ret, a); } n >>= 1; a = multiply(a, a); } return ret; } const multiply = (a, b) => { const c = new Array(2).fill(0).map(() => new Array(2).fill(0)); for (let i = 0; i < 2; i++) { for (let j = 0; j < 2; j++) { c[i][j] = (BigInt(a[i][0]) * BigInt(b[0][j]) + BigInt(a[i][1]) * BigInt(b[1][j])) % BigInt(1000000007); } } return c; }
java:
class Solution { static final int MOD = 1000000007; public int fib(int n) { if (n < 2) { return n; } int[][] q = {{1, 1}, {1, 0}}; int[][] res = pow(q, n - 1); return res[0][0]; } public int[][] pow(int[][] a, int n) { int[][] ret = {{1, 0}, {0, 1}}; while (n > 0) { if ((n & 1) == 1) { ret = multiply(ret, a); } n >>= 1; a = multiply(a, a); } return ret; } public int[][] multiply(int[][] a, int[][] b) { int[][] c = new int[2][2]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % MOD); } } return c; } }
C#:
public class Solution { const int MOD = 1000000007; public int Fib(int n) { if (n < 2) { return n; } int[,] q = {{1, 1}, {1, 0}}; int[,] res = Pow(q, n - 1); return res[0, 0]; } public int[,] Pow(int[,] a, int n) { int[,] ret = {{1, 0}, {0, 1}}; while (n > 0) { if ((n & 1) == 1) { ret = Multiply(ret, a); } n >>= 1; a = Multiply(a, a); } return ret; } public int[,] Multiply(int[,] a, int[,] b) { int[,] c = new int[2, 2]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { c[i, j] = (int) (((long) a[i, 0] * b[0, j] + (long) a[i, 1] * b[1, j]) % MOD); } } return c; } }
矩阵快速幂的算法复杂度
时间复杂度:O(logn)。
空间复杂度:O(1)。
读书笔记
我的算法不太行,我的数学也不太行。还有很大的进步空间哈哈哈哈