【LeetCode 64 C++】最小路径和

题目描述

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-path-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路1——动态规划

比较简单的动态规划题目,由于只能向下或向右移动,终点(m, n)的上一个位置只能是(m-1, n)或(m, n-1),问题转化为求从左上角到(m-1, n)和(m, n-1)的最短距离。因此,左上角到某点(i. j)的最短路径为左上角到(m-1, n)和(m, n-1)的最短路径中较小的值加上(i, j)的值,可以得到动态规划的状态转移方程为dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]。
左上角到(0, j)的只能从(0, 0)向右移动到达,因此最短路径dp[0][j] = dp[0][j-1] + grid[0][j],同理可得dp[i][0] = dp[i-1][0] + grid[i][0],这是动态规划的初始状态。将数组dp填充完毕后,即可得到最短路径dp[m-1][n-1]。

核心算法

public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        // 表示到第i行第j列的最小路径
        int dp[m][n];

        // 动态规划初始状态
        dp[0][0] = grid[0][0];
        for(int i = 1; i < n; i++){
            dp[0][i] = dp[0][i - 1] + grid[0][i];
        }
        for(int i = 1; i < m; i++){
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }

        // 状态转移方程
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                dp[i][j] = min(dp[i - 1][j] + grid[i][j], dp[i][j - 1] + grid[i][j]);
            }
        }

        return dp[m - 1][n - 1];
    }
}

解题思路2——DFS

本题也可采用深度优先搜索的方法解决,与动态规划从进到远一步一步计算最短路径相反,DFS以递归的方式先计算(m-1, n)和(m, n-1)到终点(m, n)的最短路径,再一层层向前反推。(i, j)到终点的最短路径计算公式为memo[i][j] = min(memo[i+1][j], memo[i][j+1]) + grid[i][j]。

核心算法

class Solution {
private:
    int m, n;
    int memo[100][100];

public:
    int dfs_minPathSum(vector<vector<int>>& grid) {
        m = grid.size(), n = grid[0].size();
        // 全部初始化为-1
        for (int i = 0; i < m; i++) {
            memset(memo[i], -1, sizeof(int) * n);
        }
        return dfs(grid, 0, 0);
    }

	// 深度优先搜索,返回第r行第c列到终点的最短路径
    int dfs(vector<vector<int>>& grid, int r, int c){
    	// 越界则认为距离无穷大
        if (r < 0 || r >= m || c < 0 || c >= n)
            return 1000000;
        // 若已经计算得第r行第c列到终点的最短路径,直接返回
        if(memo[r][c] != -1)
            return memo[r][c];
        // 终点到终点的最短路径
        if(r == m - 1 && c == n - 1){
            memo[r][c] = grid[m - 1][n - 1];
            return memo[r][c];
        }

        // 递归,当前最短路径为右侧或下侧位置到终点的最短路径(取较小值)加该点的值
        int right = dfs(grid, r, c + 1);
        int down = dfs(grid, r + 1, c);
        memo[r][c] = min(right, down) + grid[r][c];
        return memo[r][c];
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值