zoukankan      html  css  js  c++  java
  • 【LeetCode-动态规划】最小路径和

    题目描述

    给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
    说明:每次只能向下或者向右移动一步。
    示例:

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

    题目链接: https://leetcode-cn.com/problems/minimum-path-sum/

    思路1

    使用动态规划自顶向下来做。

    • 状态:dp[i][j]表示从左上角到位置(i,j)的最短路径;
    • 状态转移:因为每次只能向下或者向右移动一步,所以dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
    • 特殊情况:因为状态转移公式存在i-1和j-1,所以上面的状态转移公式使用的情况为i>=1, j>=1;当不满足时:
      • 当i==0并且j>0时,dp[i][j] = dp[i][j-1]+grid[i][j];
      • 当j==0并且i>0时,dp[i][j] = dp[i-1][j]+grid[i][j];

    注意,不要写成当 i==0 或者 j==0 时,dp[i][j] = grid[i][j];

    代码如下:

    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            if(grid.empty()) return 0;
    
            int rows = grid.size();
            int cols = grid[0].size();
            vector<vector<int>> dp(rows, vector<int>(cols, 0));
            dp[0][0] = grid[0][0];
            for(int i=0; i<rows; i++){
                for(int j=0; j<cols; j++){
                    if(i==0){   // 第0行,没有上一行
                        if(j-1>=0){
                            dp[i][j] = dp[i][j-1] + grid[i][j];
                        }
                    }else if(j==0){ // 第0列,没有上一列
                        if(i-1>=0){
                            dp[i][j] = dp[i-1][j] + grid[i][j];
                        }
                    }else{
                        dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
                    }
                }
            }
            return dp[rows-1][cols-1];
        }
    };
    
    • 时间复杂度:O(mn)
    • 空间复杂度:O(mn)

    思路2

    使用动态规划自底向上做。
    分析过程和上面的过程类似,状态转移方程为dp[i][j] = min(dp[i+1][j], dp[i][j+1]) + grid[i][j],注意边界情况即可。代码如下:

    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            if(grid.empty()) return 0;
    
            int rows = grid.size();
            int cols = grid[0].size();
            vector<vector<int>> dp(rows, vector<int>(cols, 0));
    
            for(int i=rows-1; i>=0; i--){
                for(int j=cols-1; j>=0; j--){
                    if(i==rows-1){  // 最后一行
                        if(j==cols-1) dp[i][j] = grid[i][j];
                        else dp[i][j] = dp[i][j+1] + grid[i][j];
                    }else if(j==cols-1){    // 最后一列
                        if(i==rows-1) dp[i][j] = grid[i][j];
                        else dp[i][j] = dp[i+1][j] + grid[i][j];
                    }else{
                        dp[i][j] = min(dp[i+1][j], dp[i][j+1]) + grid[i][j];
                    }
                }
            }
            return dp[0][0];
        }
    };
    
    • 时间复杂度:O(mn)
    • 空间复杂度:O(mn)

    思路3

    在思路2中,不设置dp数组,在原数组上进行动态规划(将思路2中的dp替换为grid即可),这样就可以将空间复杂度降为O(1)。代码如下:

    class Solution {
    public:
        int minPathSum(vector<vector<int>>& grid) {
            if(grid.empty()) return 0;
    
            int rows = grid.size();
            int cols = grid[0].size();
            //vector<vector<int>> dp(rows, vector<int>(cols, 0));
    
            for(int i=rows-1; i>=0; i--){
                for(int j=cols-1; j>=0; j--){
                    if(i==rows-1){  // 最后一行
                        if(j==cols-1) grid[i][j] = grid[i][j];
                        else grid[i][j] = grid[i][j+1] + grid[i][j];
                    }else if(j==cols-1){    // 最后一列
                        if(i==rows-1) grid[i][j] = grid[i][j];
                        else grid[i][j] = grid[i+1][j] + grid[i][j];
                    }else{
                        grid[i][j] = min(grid[i+1][j], grid[i][j+1]) + grid[i][j];
                    }
                }
            }
            return grid[0][0];
        }
    };
    
    • 时间复杂度:O(mn)
    • 空间复杂度:O(1)

    相关题目

    1、三角形路径最小和:https://www.cnblogs.com/flix/p/12747902.html

  • 相关阅读:
    Js--小笔记
    Android Gson解析
    java格式化数字、货币、金钱
    关于Edittext默认弹出软键盘为数字键
    生日星座自动匹配
    ANDROID STUDIO系列教程六--GRADLE多渠道打包
    框架,简化了代码的同时,也让我们慢慢变蠢
    Android开发实现高德地图定位
    onNewIntent调用时机
    EditText输入手机号自动带空格
  • 原文地址:https://www.cnblogs.com/flix/p/12753316.html
Copyright © 2011-2022 走看看