代码随想录第十七天|动态规划(1)

目录

LeetCode 509. 斐波那契数列

LeetCode 70. 爬楼梯

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

LeetCode 62. 不同路径

LeetCode 63. 不同路径 II

总结


动态规划在算法课上学习过,看过了之后有一些熟悉感。(虽然贪心算法也学过,但是不如动态规划这样有统一的想法。)

对于动态规划问题,可以拆解为以下五步:

  1. 确定dp数组以及下标的含义
  2. 确定递推公式
  3. dp数组如何进行初始化
  4. 确定dp数组的遍历顺序
  5. 举例推导dp数组

在写题解的时候,基本上就按照这五步来写

LeetCode 509. 斐波那契数列

题目链接:LeetCode 509. 斐波那契数列

思想:本题的dp数组很明显,就是斐波那契数列;递推公式就是dp[i] = dp[i-1]+dp[i-2];初始化也很简单,dp[0]=0,dp[1]=1;遍历顺序的话就是从第二项遍历到第n项,如果n<2的话,就可以直接return n;同时,因为一次的遍历只涉及三个数,且只需要返回第n项的斐波那契值。所以dp数组的大小可以只设置为2。

代码如下:

    int fib(int n) {
        if (n <= 1) return n;
        int dp[2];
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }

时间复杂度:O(n),空间复杂度:O(1)。

LeetCode 70. 爬楼梯

题目链接:LeetCode 70. 爬楼梯

思想:本题其实与斐波那契数列十分相似,到达i层的话有dp[i]种方法,而到达i层可以通过i-1层爬一楼,通过i-2层爬两楼,所以本题的递推公式就是dp[i]=dp[i-1]+dp[i-2]。dp数组的话就是到达每一层楼有多少种方法,初始化就是到达第一层有一种,到达第二层有两种方法,即dp[0]=1,dp[1]=2;遍历就是从第三层到第n层了。

代码如下:

    int climbStairs(int n) {
        if (n == 1) return n;
        int dp[2];
        dp[0] = 1;
        dp[1] = 2;
        int flood = 2;
        while (flood++ != n) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }

时间复杂度:O(n),空间复杂度:O(1)。

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

题目链接:LeetCode 746. 使用最小花费爬楼梯

思想:本题的dp数组应该是到达该阶梯需要支付的最小费用,下标就是台阶;递推公式的话,应该是到这一层所需要支付的最小费用,到第i层的话,需要在第i-1爬一楼或者在第i-2爬两楼,最小费用的就取这两个的最小值并且要加上本身;dp数组的初始化就是应该等于cost;遍历也是从dp的第三项开始;在调试的时候,发现结果数组会把最后一项的数加上,这是因为题目中的楼顶是数组尺寸+1,所以应该要往dp数组里面再加一个元素,加0就行了。

代码如下:

    int minCostClimbingStairs(vector<int>& cost) {
        vector<int> dp = cost;
        dp.push_back(0);
        for (int i = 2; i < dp.size(); i++) {
            dp[i] += min(dp[i - 1], dp[i - 2]); 
        }
        return dp[dp.size() - 1];
    }

时间复杂度:O(n),空间复杂度:O(n)。

LeetCode 62. 不同路径

题目链接:LeetCode 62. 不同路径

思想:本题十分熟悉,是动态规划的经典题,看了一眼就想起来了。dp数组就是表示到当前这个格子可以通过多少条路;一个格子只能由它的左边或者上边达到,所以dp[i][j]=dp[i-1][j]+dp[i][j-1];关于dp的初始化,对于棋盘边上的数组即左上角往右走的一条路和左上角往下走的一条路,其值都应该等于1;最后遍历就遍历整个dp数组就行了。

代码如下:

    int uniquePaths(int m, int n) {
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (j - 1 < 0 || i - 1 < 0) {
                    dp[i][j] = 1;
                } else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];
    }

时间复杂度:O(n^2),空间复杂度:O(n^2)。

LeetCode 63. 不同路径 II

题目链接:LeetCode 63. 不同路径 II

思想:本题对于上题基本上是一模一样的,但是有一个特别不同,就是初始化。上一题的初始化是沿着边框线全部初始化为1,但本题不一样,如果在边框线上有障碍物的话,障碍物以及障碍物以后的dp数组应该全为0。

代码如下:

    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if (obstacleGrid[0][0] == 1) return 0;
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        vector<vector<int>> dp(m, vector<int>(n, 0));
        for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
        for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (obstacleGrid[i][j] == 1) {
                    continue;
                }
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        return dp[m - 1][n - 1];
    }

时间复杂度:O(n^2),空间复杂度:O(n^2)。

总结

刷到动态规划的话,也算是到了熟悉的领域了。贪心算法有些实在是想不出来。

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值