代码随想录Day32-动态规划:力扣第509e、70e、746e、62m、63m题

509e. 斐波那契数

题目链接
代码随想录文章讲解链接

方法一:递归

用时:1m20s

思路

很帅,但时间复杂度很高。

  • 时间复杂度: O ( 2 n ) O(2^n) O(2n)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int fib(int n) {
    	return n < 2 ? n : fib(n - 1) + fib(n - 2);
    }
};

方法二:动态规划

用时:2m30s

思路

状态转移方程:dp[i] = dp[i-1] + dp[i-2]
dp数组初始化:dp[0] = 0, dp[1] = 1

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int pre1 = 0, pre2 = 1;
        int tmp = 0;
        for (int i = 2; i <= n; ++i) {
            tmp = pre2;
            pre2 = pre1 + pre2;
            pre1 = tmp;
        }
        return pre2;
    }
};

方法三:面向结果编程(bushi

思路
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 3;
        if (n == 5) return 5;
        if (n == 6) return 8;
        if (n == 7) return 13;
        if (n == 8) return 21;
        if (n == 9) return 34;
        if (n == 10) return 55;
        if (n == 11) return 89;
        if (n == 12) return 144;
        if (n == 13) return 233;
        if (n == 14) return 377;
        if (n == 15) return 610;
        if (n == 16) return 987;
        if (n == 17) return 1597;
        if (n == 18) return 2584;
        if (n == 19) return 4181;
        if (n == 20) return 6765;
        if (n == 21) return 10946;
        if (n == 22) return 17711;
        if (n == 23) return 28657;
        if (n == 24) return 46368;
        if (n == 25) return 75025;
        if (n == 26) return 121393;
        if (n == 27) return 196418;
        if (n == 28) return 317811;
        if (n == 29) return 514229;
        return 832040;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


70e. 爬楼梯

题目链接
代码随想录文章讲解链接

方法一:动态规划

思路
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        int pre1 = 1, pre2 = 2;
        int tmp = 0;
        for (int i = 3; i <= n; ++i) {
            tmp = pre2;
            pre2 = pre1 + pre2;
            pre1 = tmp;
        }
        return pre2;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


746e. 使用最小花费爬楼梯

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:8m18s

思路

dp数组:dp[i]表示爬到第i阶楼梯需要的最小费用
状态转移方程:dp[i] = min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1])
dp数组初始化:dp[0] = 0, dp[1] = 0

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int preCost1 = 0, preCost2 = 0;
        int tmp = 0;
        for (int i = 2; i <= cost.size(); ++i) {
            tmp = preCost2;
            preCost2 = min(cost[i - 2] + preCost1, cost[i - 1] + preCost2);
            preCost1 = tmp;
        }
        return preCost2;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


62m. 不同路径

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:11m24s

思路

dp数组:二维dp数组,dp[i][j]表示机器人移动到(i,j)个网格的路径数
状态转移方程:dp[i][j] = dp[i-1][j] + dp[i][j-1](注意边界情况)
dp数组初始化:dp[0][0] = 1
遍历顺序:优先从左往右,其次从上到下,或者优先从上到下,其次从左往右都行

  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度: O ( m ∗ n ) O(m*n) O(mn)
C++代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 1));
        for (int i = 0; i < m; ++i) {
            for (int j = i == 0 ? 1 : 0; j < n; ++j) {
                if (i - 1 < 0) dp[i][j] = dp[i][j - 1];
                else if (j - 1 < 0) dp[i][j] = dp[i - 1][j];
                else dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m - 1][n - 1];
    }
};

方法二:动态规划+滚动数组

思路

方法一的空间复杂度可以优化,在从左往右、从上往下遍历的时候,先前的行的路径数已经不再需要了,所以可以不用记录,我们可以只用一个一维数组来记录上一行的路径数,并在遍历的时候更新即可。

  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int> dp(n, 1);
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) dp[j] += dp[j - 1];
        }
        return dp[n - 1];
    }
};

方法三:动态规划+滚动数组(极致优化)

思路

判断行和列哪个小,然后用不同的遍历顺序,这样一维数组的空间就能更小。

  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))
C++代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        if (m > n) {
            vector<int> dp(n, 1);
            for (int i = 1; i < m; ++i) {
                for (int j = 1; j < n; ++j) dp[j] += dp[j - 1];
            }
            return dp[n - 1];
        } else {
            vector<int> dp(m, 1);
            for (int j = 1; j < n; ++j) {
                for (int i = 1; i < m; ++i) dp[i] += dp[i - 1];
            }
            return dp[m - 1];
        }
    }
};

方法四:数论

思路

从左上角走到右下角无论怎么走,一定需要m+n-2步,且其中m-1步为向下走,n-1步为向右走,所以不同的路径数量就相当于走m+n-2步中选取m-1步向下走,n-1步向右走的数量,即为组合数 C m + n − 2 m − 1 = C m + n − 2 n − 1 = ( m + n − 2 ) ! ( m − 1 ) ! ( n − 1 ) ! = ( m + n − 2 ) ( m + n − 3 ) . . . n ( m − 1 ) ( m − 2 ) . . . 1 C_{m+n-2}^{m-1}=C_{m+n-2}^{n-1}=\frac{(m+n-2)!}{(m-1)!(n-1)!}=\frac{(m+n-2)(m+n-3)...n}{(m-1)(m-2)...1} Cm+n2m1=Cm+n2n1=(m1)!(n1)!(m+n2)!=(m1)(m2)...1(m+n2)(m+n3)...n
题目转化为求该组合数,分子从1开始一直乘到m-1,有m-1个数,分母从n开始,一直乘到m+n-2,同样有m-1个数。

  • 时间复杂度: O ( m ) O(m) O(m)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long res = 1;
        int x = n;  // 分子
        int y = 1;  // 分母
        while (y < m) {
            res *= x++;
            res /= y++;
        }
        return res;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


63m. 不同路径 II

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:17m59s

思路

与上一题62m差不多,只是增加多一个条件,当某个位置有障碍的时候,到达此处的路径数为0。

  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        vector<int> dp(n, 0);
        // 初始化dp数组
        for (int j = 0; j < n; ++j) {
            if (obstacleGrid[0][j] == 1) break;
            dp[j] = 1;
        }
        // 遍历
        for (int i = 1; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (obstacleGrid[i][j] == 1) dp[j] = 0;
                else if (j > 0) dp[j] += dp[j - 1];
            }
        }
        return dp[n - 1];
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


最后的碎碎念

dp第一天,还行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值