20200613
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
给定 n 是一个正整数。
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
// 3
1->3 2->3 => f(3)=f(1)+f(2)
// 4
2->4 3->4 => f(4)=f(2)+f(3)
// 5
3->5 4->5 => f(5)=f(3)+f(4)
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
if (n < 2) return 1;
if (n === 2) return 2;
let map = new Map([[0, 1], [1, 1]]);
for (let i = 2; i < n + 1; i++) {
map.set(i, map.get(i - 2) + map.get(i - 1));
}
return map.get(n);
};
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let p = 0, q = 0, r = 1;
for (let i = 1; i <= n; ++i) {
p = q;
q = r;
r = p + q;
}
return r;
};
构建这样一个递推关系:
∣ 1 1 1 0 ∣ ∣ f ( n ) f ( n − 1 ) ∣ = ∣ f ( n ) + f ( n − 1 ) f ( n ) ∣ = ∣ f ( n + 1 ) f ( n ) ∣ \begin{vmatrix} \mathbf{1} & \mathbf{1} \\ \mathbf{1} & \mathbf{0} \\ \end{vmatrix} \begin{vmatrix} \mathbf{f(n)} \\ \mathbf{f(n-1)} \\ \end{vmatrix}= \begin{vmatrix} \mathbf{f(n)+f(n-1)} \\ \mathbf{f(n)} \\ \end{vmatrix}= \begin{vmatrix} \mathbf{f(n+1)} \\ \mathbf{f(n)} \\ \end{vmatrix} ∣∣∣∣1110∣∣∣∣∣∣∣∣f(n)f(n−1)∣∣∣∣=∣∣∣∣f(n)+f(n−1)f(n)∣∣∣∣=∣∣∣∣f(n+1)f(n)∣∣∣∣
因此:
∣ f ( n + 1 ) f ( n ) ∣ = ∣ 1 1 1 0 ∣ n ∣ f ( 1 ) f ( 0 ) ∣ \begin{vmatrix} \mathbf{f(n+1)} \\ \mathbf{f(n)} \\ \end{vmatrix}= \begin{vmatrix} \mathbf{1} & \mathbf{1} \\ \mathbf{1} & \mathbf{0} \\ \end{vmatrix}^n \begin{vmatrix} \mathbf{f(1)} \\ \mathbf{f(0)} \\ \end{vmatrix} ∣∣∣∣f(n+1)f(n)∣∣∣∣=∣∣∣∣1110∣∣∣∣n∣∣∣∣f(1)f(0)∣∣∣∣
令:
M = ∣ 1 1 1 0 ∣ M= \begin{vmatrix} \mathbf{1} & \mathbf{1} \\ \mathbf{1} & \mathbf{0} \\ \end{vmatrix} M=∣∣∣∣1110∣∣∣∣
因此我们只要能快速计算矩阵 M 的 n 次幂,就可以得到 f(n) 的值。如果直接求取 M n M^n Mn
时间复杂度是 O(n) 的,我们可以定义矩阵乘法,然后用快速幂算法来加速这里 M n M^n Mn的求取
如何想到使用矩阵快速幂?
我们可以做这样的变换:
f ( x ) + x c = [ f ( x − 1 ) + ( x − 1 ) c ] + [ f ( x − 2 ) + ( x − 2 ) c ] + [ f ( x − 3 ) + ( x − 3 ) c ] f(x)+xc=[f(x−1)+(x−1)c]+[f(x−2)+(x−2)c]+[f(x−3)+(x−3)c] f(x)+xc=[f(x−1)+(x−1)c]+[f(x−2)+(x−2)c]+[f(x−3)+(x−3)c]
令 g ( x ) = f ( x ) + x c g(x) = f(x) + xc g(x)=f(x)+xc,那么我们又得到了一个齐次线性递:
g ( x ) = g ( x − 1 ) + g ( x − 2 ) + g ( x − 3 ) g(x) = g(x - 1) + g(x - 2) + g(x - 3) g(x)=g(x−1)+g(x−2)+g(x−3)
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
var q = [[1, 1], [1, 0]];
var res = pow(q, n);
function pow(a, n) {
var ret = [[1, 0], [0, 1]];
while (n > 0) {
if ((n & 1) == 1) {
ret = multiply(ret, a);
}
n >>= 1;
a = multiply(a, a);
}
return ret;
}
function multiply(a, b) {
var c = [Array(2), Array(2)];
for (var i = 0; i < 2; i++) {
for (var j = 0; j < 2; j++) {
c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
}
}
return c;
}
return res[0][0];
};
根据递推方程 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n - 1) + f(n - 2) f(n)=f(n−1)+f(n−2),我们可以写出这样的特征方程:
x 2 = x + 1 x^2 = x + 1 x2=x+1
求得: x 1 = 1 + 5 2 , x 2 = 1 − 5 2 x_1 = \frac{1+\sqrt{5}}{2},x_2 = \frac{1-\sqrt{5}}{2} x1=21+5,x2=21−5,设通解为 : f ( n ) = c 1 n + c 2 n f(n) = c_1^n + c_2^n f(n)=c1n+c2n ,代入初始条件 f(1) = 1f,f(2) = 1,得: c 1 = 1 5 , c 2 = − 1 5 c_1 = \frac{1}{\sqrt{5}},c_2 = -\frac{1}{\sqrt{5}} c1=51,c2=−51,我们得到了这个递推数列的通项公式:
f ( n ) = 1 5 [ ( 1 − 5 y ) n − ( 1 + 5 y ) n ] f(n) = \frac 1{\sqrt{5}}[(\frac {1-\sqrt{5}}y)^n-(\frac {1+\sqrt{5}}y)^n] f(n)=51[(y1−5)n−(y1+5)n]
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
var sqrt5 = Math.sqrt(5);
var fibn = Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1);
return parseInt(fibn / sqrt5);
};
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
var a = 1;
var b = 1;
while(n--){
a = (b+=a) -a;
}
return a;
};
港真矩阵快速幂和通项公式确实没看懂,数学不行真是不行呀
路漫漫其修远兮
博客: 小书童博客(http://gaowenju.com/)