动态规划 70.climbing Stairs ,120,64

1. 记忆化搜索 - 自上向下的解决问题:使用vector来保存每次计算的结果,如果下次再碰到同样的需要计算的式子就不需要重复计算了。

2. 动态规划 - 自下向上的解决问题

 

 解法一:自顶向下

解法二:自底向上

class Solution {

private:
    vector<int> memo;
    
    int calcWays(int n){
        
        if(n==0) return 1;   //一个台阶都没有
        if(n==1) return 1;
        //if(n==2) return 2; //有两种解决方法:一次迈一步,迈两次;一次迈两步
        if(memo[n] == -1)
            memo[n] = calcWays(n-1) + calcWays(n-2);  
        //在第n-1阶台阶迈一步或者在第n-2阶台阶迈两步
        return memo[n];
    }
    
public:
    int climbStairs(int n) {
        //n为台阶数
        memo = vector<int>(n+1,-1);   //memo初始化为n+1个-1
        return calcWays(n);
    }
};
class Solution {
    
public:
    int climbStairs(int n) {
        //n为台阶数
        vector<int> memo(n+1,-1);   //memo初始化为n+1个-1
        memo[0] = memo[1] = 1;
        for(int i=2;i<=n;i++)
            memo[i] = memo[i-1] + memo[i-2];
        return memo[n];
    }
};

注意:从2只能移动到3和4;从3只能移动到6和5.

思路:设从位置(i,j)达到底部的最小路径和为MP(i,j);根据约束条件,从位置(i,j)只能达到下一行的(i+1,j)和(i+1,j+1)两个位置;

 前面的思路是自顶向下的,如果采用自底向上的求解思路,最后的sum[0]是要的结果。可以申请一个一维数组初始化为三角形数阵底部向量,逐步向上计算更新,空间复杂度为O(n)

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int length = triangle.size();
        if(length==0) return 0;
        if(length==1) return triangle[0][0];
        vector<int> sum = triangle[length-1];   //初始化sum为三角形底部的向量
        
        for(int i=length-2;i>=0;i--){
            for(int j=0;j<triangle[i].size();j++)
                sum[j] = min(triangle[i][j]+sum[j], triangle[i][j]+sum[j+1]);
        }
        
        return sum[0];
    }
};

这个解法是重做了一遍题想到的,感觉比上一个解法有点麻烦,还容易索引溢出。

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        if(triangle.empty()) return 0;
        int row = triangle.size();
        int column = triangle[row-1].size();
        int dp[row][column+1];
        for(int i=0; i<row; i++){
            for(int j=0; j<column+1; j++){
                dp[i][j] = INT_MAX;
            }
        }
        dp[0][1] = triangle[0][0];
        
        for(int i = 1; i < row; i++){
            for(int j=1; j<=i+1; j++){
                
                dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j-1];
            }
        }
        
        sort(dp[row-1], dp[row-1]+column+1);
        return dp[row-1][0];
    }
};

 

 

题目:给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例:

输入:
[[1,3,1],
[1,5,1],
[4,2,1]]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

思路

以输入为 3*3 的网格为例,其中 m=3,n=3
[1,3,1]
[1,5,1]
[4,2,1]
由于每次只能向下或者向右移动,则每一步结果为当前值+min(上边一步,左边一步),即 dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])

注意:不要忘记dp[0][0]的初始化。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.size() == 0) return 0;
        int m = grid.size();
        int n = grid[0].size();
        int dp[m][n];   //m行n列的一个二维数组
        dp[0][0] = grid[0][0];
        //初始化边界
        for(int i = 1; i<m; i++){
            dp[i][0] = grid[i][0] + dp[i-1][0];   //最左边一列的值只能是当前格子+上面一个
        }
        for(int i=1;i<n;i++){
            dp[0][i] = grid[0][i] + dp[0][i-1];   //最上面一行的值只能是当前格子+左边一个
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++)
                dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]);
        }
        
        return dp[m-1][n-1];
    }
};

 解法二:又做了一遍,自己想出来了思路

1)设置一维数组 dp[i] 为 当前行存储的到该索引的最小和;

2)初始化dp为grid的第一行,即  dp[0] = grid[0][0]; 然后接下来dp[i] = dp[i-1] + grid[0][i];

3) 状态方程:dp[j] = min(dp[j-1]+grid[i][j], dp[j]+grid[i][j]); //取左边或上面到该索引的最小值

4)dp最左边一列只能从上面走到。

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int n = grid.size();
        int m = grid[0].size();
        int dp[m] = {};
        dp[0] = grid[0][0];
        for(int i=1; i<m;i++){
            dp[i] = dp[i-1] + grid[0][i];
            
        }
        
        for(int i=1; i<n; i++){
            for(int j=0; j<m ; j++){
                if(j==0)
                    dp[j] = dp[j] + grid[i][j];
                else{
                    dp[j] = min(dp[j-1]+grid[i][j], dp[j]+grid[i][j]);
                }
            }
        }
        return dp[m-1];
    }
};

 

转载于:https://www.cnblogs.com/Bella2017/p/10182532.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值