https://leetcode-cn.com/problems/climbing-stairs/solution/pa-lou-ti-by-leetcode-solution/

Idea

这个题其实就是斐波那契数列
初始条件F[1]=1 F[2]=2
dp方程为爬楼梯 - 图1

对于这样的方程 我们可以用动态规划写出一个时间空间复杂度都为爬楼梯 - 图2的算法

但是 对与这样的一次线性递推方程 我们可以用滚动数组来优化空间复杂度

Code

  1. class Solution {
  2. public int climbStairs(int n) {
  3. int p = 0, q = 0, r = 1;
  4. for (int i = 1; i <= n; ++i) {
  5. p = q;
  6. q = r;
  7. r = p + q;
  8. }
  9. return r;
  10. }
  11. }

优化思路

对于斐波那契数列的递推方程 我们可以用矩阵表示为
爬楼梯 - 图3
由于此题中F[1]=1 F[2]=2
可以得到
爬楼梯 - 图4
又因为 矩阵爬楼梯 - 图5的值有一个特性 就是爬楼梯 - 图6 c+d=a
因此当矩阵乘以[1,1]的时候 可以直接再乘以一个矩阵来替代 也就是直接求矩阵的n次方就可以了

因此 我们可以用矩阵快速幂把这道题优化到爬楼梯 - 图7

  1. public class Solution {
  2. public int climbStairs(int n) {
  3. int[][] q = {{1, 1}, {1, 0}};
  4. int[][] res = pow(q, n);
  5. return res[0][0];
  6. }
  7. public static int[][] pow(int[][] a, int n) {
  8. int[][] ret = {{1, 0}, {0, 1}}; //单位矩阵
  9. while (n > 0) {
  10. if ((n & 1) == 1) { //(n & 1) == 1 判断n是否为奇数 n为奇数的话二进制最低位一定为1 1 and 1还是1
  11. ret = multiply(ret, a);
  12. }
  13. n >>= 1; //>> 右移运算符 比如n=77=1001101 右移之后 变成100110
  14. a = multiply(a, a); //同时 a需要对自己进行平方 因为右移之后 相当于增加了2的平方
  15. }
  16. return ret;
  17. }
  18. public int[][] multiply(int[][] a, int[][] b) {
  19. int[][] c = new int[2][2];
  20. for (int i = 0; i < 2; i++) {
  21. for (int j = 0; j < 2; j++) {
  22. c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
  23. }
  24. }
  25. return c;
  26. }
  27. }