题目
解题
以下题目解题方法相同,区别点是根据题干,动态转移方程会有差异。
题目 | 解题 |
---|---|
面试题 08.01. 三步问题 | 三步问题题解 |
剑指 Offer 10- I. 斐波那契数列 | 斐波那契数列题解 |
70. 爬楼梯 | 爬楼梯 |
剑指Offer 10- II 青蛙跳台阶问题 | 青蛙跳台阶问题 |
解题一:动态规划
// javascript
var fib = function(n) {
if (n < 2) return n;
const MOD = 1e9 + 7;
let p = 0, q = 1, r;
for (let i = 2; i <= n; ++i) {
r = (p + q) % MOD;
p = q;
q = r;
}
return r;
};
自上而下的记忆化搜索:
// javascript
var fib = function(n) {
const MOD = 1e9 + 7;
const record = new Map();
record.set(0, 0);
record.set(1, 1);
const findFib = (n) => {
if (record.has(n) === false) {
const val = (findFib(n - 1) + findFib(n - 2)) % MOD;
record.set(n, val);
}
return record.get(n);
};
return findFib(n);
};
空间复杂度: O ( n ) O(n) O(n),递归 + 记录结果的哈希表的额外空间。
解题二:矩阵快速幂
[
F
(
n
)
F
(
n
−
1
)
]
=
[
1
1
0
1
]
n
−
1
∗
[
F
(
1
)
F
(
0
)
]
,
令
A
=
[
a
b
c
d
]
=
[
1
1
0
1
]
n
−
1
\begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} = {\begin{bmatrix} 1 & 1 \\ 0 & 1\end{bmatrix}}^{n-1} * \begin{bmatrix} F(1) \\ F(0) \end{bmatrix}, 令 A = \begin{bmatrix} a & b \\ c & d \end{bmatrix} = {\begin{bmatrix} 1 & 1 \\ 0 & 1\end{bmatrix}}^{n-1}
[F(n)F(n−1)]=[1011]n−1∗[F(1)F(0)],令A=[acbd]=[1011]n−1
[ F ( n ) F ( n − 1 ) ] = [ a b c d ] ∗ [ F ( 1 ) F ( 0 ) ] = [ a b c d ] ∗ [ 1 0 ] = [ a c ] \begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} * \begin{bmatrix} F(1) \\ F(0) \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} * \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} a \\ c \end{bmatrix} [F(n)F(n−1)]=[acbd]∗[F(1)F(0)]=[acbd]∗[10]=[ac]
因此 F ( n ) = a = A [ 0 ] [ 0 ] F(n) = a = A[0][0] F(n)=a=A[0][0]。
注意要使用 BigInt 类型。
// javascript
var fib = function(n) {
if (n < 2) return n;
const q = [[1, 1], [1, 0]];
const res = matpow(q, n - 1);
return res[0][0];
};
// const matpow = (a, n) => {
// if (n === 1) return a;
// const b = matpow(a, n >> 1);
// let res = matmul(b, b);
// if (n % 2 === 1) {
// res = matmul(res, a);
// }
// return res;
// };
const matpow = (a, n) => {
let ret = [[1, 0], [0, 1]];
// 以 7 (0b111) 为例,a^7 = a^4 + a^2 + a^1
while (n > 0) {
if ((n & 1) === 1) {
ret = matmul(ret, a);
}
n >>= 1;
a = matmul(a, a);
}
return ret;
};
const matmul = (a, b) => {
const m1 = a.length, n1 = a[0].length;
const m2 = b.length, n2 = b[0].length;
if (n1 !== m2) {
throw new Error('these 2 matrix can not be multiplied!');
}
// 初始化时要用 BigInt 类型 => 数字后面加 n
const res = new Array(m1).fill(0n).map(() => new Array(n2).fill(0n));
for (let i = 0; i < m1; ++i) {
for (let j = 0; j < n2; ++ j) {
for (let k = 0; k < n1; ++k) {
res[i][j] += BigInt(a[i][k]) * BigInt(b[k][j]);
}
// 结果取模
res[i][j] %= BigInt(1e9 + 7);
}
}
return res;
};