• 动态规划 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];
        }
    };
  • 相关阅读:
    洛谷3004 [USACO10DEC]宝箱Treasure Chest
    洛谷3778 [APIO2017]商旅
    洛谷4141消失之物——每个体积的角度
    洛谷2943 [USACO09MAR]清理Cleaning Up——转变枚举内容的dp
    bzoj1858[Scoi2010]序列操作
    poj1325机器工作——二分图最小点覆盖
    洛谷P1144——最短路计数
    poj3254二进制放牛——状态压缩DP
    poj1191棋盘分割——区间DP
    洛谷P1474货币系统——背包方案计数
  • 原文地址:https://www.cnblogs.com/Bella2017/p/10182532.html
Copyright © 2020-2023  润新知