动态规划与矩阵对角化
题目描述:
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
链接:https://leetcode-cn.com/problems/climbing-stairs/
本文重点给出递推方程对角化的求解
易知求n阶楼梯走法,有两种选择,其递推方程为
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
f(n) = f(n - 1) + f(n - 2)
f(n)=f(n−1)+f(n−2)
建立方程组:
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
f
(
n
−
1
)
=
f
(
n
−
1
)
\begin{aligned} f(n) & = f(n - 1) + f(n - 2) \\ f(n - 1) & = f(n - 1) \\ \end{aligned}
f(n)f(n−1)=f(n−1)+f(n−2)=f(n−1)
其矩阵形式为:
[ 1 1 1 0 ] [ f ( n − 1 ) f ( n − 2 ) ] = [ f ( n ) f ( n − 1 ) ] \left[ {\begin{array}{ccccccccccccccc}1&1\\1&0\end{array}} \right]\left[ {\begin{array}{ccccccccccccccc}{f(n - 1)}\\{f(n - 2)}\end{array}} \right] = \left[ {\begin{array}{ccccccccccccccc}{f(n)}\\{f(n - 1)}\end{array}} \right] [1110][f(n−1)f(n−2)]=[f(n)f(n−1)]
根据递推我们可以得到
[
1
1
1
0
]
n
−
1
[
f
(
2
)
f
(
1
)
]
=
[
f
(
n
)
f
(
n
−
1
)
]
{\left[ {\begin{array}{ccccccccccccccc}1&1\\1&0\end{array}} \right]^{n - 1}}\left[ {\begin{array}{ccccccccccccccc}{f(2)}\\{f(1)}\end{array}} \right] = \left[ {\begin{array}{ccccccccccccccc}{f(n)}\\{f(n - 1)}\end{array}} \right]
[1110]n−1[f(2)f(1)]=[f(n)f(n−1)]
对于计算矩阵的n次幂,如果矩阵可以对角化,可以使用对角化简化计算。
对角化过程
通过
(
A
−
λ
E
)
x
=
0
(A - \lambda E)x = 0
(A−λE)x=0,我们可以得到其两个特征值为
1
+
5
2
\frac{{1 + \sqrt 5 }}{2}
21+5和
1
−
5
2
\frac{{1 - \sqrt 5 }}{2}
21−5,相应的特征向量分别为
[
1
+
5
2
1
]
和
[
1
−
5
2
1
]
\left[ {\begin{array}{ccccccccccccccc}{\frac{{1 + \sqrt 5 }}{2}}\\1\end{array}} \right]和\left[ {\begin{array}{ccccccccccccccc}{\frac{{1 - \sqrt 5 }}{2}}\\1\end{array}} \right]
[21+51]和[21−51]
同时求得特征向量矩阵的逆矩阵为
1
5
[
1
−
1
5
−
1
2
5
+
1
2
]
\frac{1}{{\sqrt 5 }}\left[ {\begin{array}{ccccccccccccccc}1&{ - 1}\\{\frac{{\sqrt 5 - 1}}{2}}&{\frac{{\sqrt 5 + 1}}{2}}\end{array}} \right]
51[125−1−125+1]
所以
[
1
1
1
0
]
n
−
1
=
1
5
[
1
+
5
2
1
−
5
2
1
1
]
[
(
1
+
5
2
)
n
−
1
0
0
(
1
−
5
2
)
n
−
1
]
[
1
−
1
5
−
1
2
5
+
1
2
]
{\left[ {\begin{array}{ccccccccccccccc}1&1\\1&0\end{array}} \right]^{n - 1}} = \frac{1}{{\sqrt 5 }}\left[ {\begin{array}{ccccccccccccccc}{\frac{{1 + \sqrt 5 }}{2}}&{\frac{{1 - \sqrt 5 }}{2}}\\1&1\end{array}} \right]\left[ {\begin{array}{ccccccccccccccc}{{{(\frac{{1 + \sqrt 5 }}{2})}^{n - 1}}}&0\\0&{{{(\frac{{1 - \sqrt 5 }}{2})}^{n - 1}}}\end{array}} \right]\left[ {\begin{array}{ccccccccccccccc}1&{ - 1}\\{\frac{{\sqrt 5 - 1}}{2}}&{\frac{{\sqrt 5 + 1}}{2}}\end{array}} \right]
[1110]n−1=51[21+5121−51][(21+5)n−100(21−5)n−1][125−1−125+1]
源码如下:
class Solution {
public int climbStairs(int n) {
double sqrt5=Math.sqrt(5);
double[][] eigenMatrix={{(sqrt5+1)/2,(1-sqrt5)/2},{1,1}};
double[][] eigenMatrixInv={{1,(sqrt5-1)/2},{-1,(sqrt5+1)/2}};//特征向量矩阵的逆/sqrt5
double[][] lambda={{Math.pow((sqrt5+1)/2,n-1),0},{0,Math.pow((1-sqrt5)/2,n-1)}};//特征值对角矩阵
double[][] muliply=matrixMultiply(matrixMultiply(eigenMatrix,lambda),eigenMatrixInv);
double result=(2*muliply[1][0]+1*muliply[1][1])/sqrt5;
return (int)Math.round(result);
}
public double[][] matrixMultiply(double[][] a,double[][] b){
double[][] result=new double[a.length][b[0].length];
double[] colOfB=new double[b[0].length];
for(int i=0;i<a.length;i++){
for(int j=0;j<b[0].length;j++){
for(int k=0;k<b.length;k++)
colOfB[k]=b[k][j];
result[i][j]=vectorMultiply(a[i],colOfB);
}
}
return result;
}
public double vectorMultiply(double[] a,double[] b){
double result=0.0;
for(int i=0;i<a.length;i++){
result+=a[i]*b[i];
}
return result;
}
}