Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example:

Input:
[
  [1,3,1],
[1,5,1],
[4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.

这道题给了我们一个只有非负数的二维数组,让找一条从左上到右下的路径,使得路径和最小,限定了每次只能向下或者向右移动。一个常见的错误解法就是每次走右边或下边数字中较小的那个,这样的贪婪算法获得的局部最优解不一定是全局最优解,因此是不行的。实际上这道题跟之前那道 Dungeon Game 没有什么太大的区别,都需要用动态规划 Dynamic Programming 来做,这应该算是 DP 问题中比较简单的一类,我们维护一个二维的 dp 数组,其中 dp[i][j] 表示到达当前位置的最小路径和。接下来找状态转移方程,因为到达当前位置 (i, j)  只有两种情况,要么从上方 (i-1, j) 过来,要么从左边 (i, j-1) 过来,我们选择 dp 值较小的那个路径,即比较 dp[i-1][j] 和 dp[i][j-1],将其中的较小值加上当前的数字 grid[i][j],就是当前位置的 dp 值了。但是有些特殊情况要提前赋值,比如起点位置,直接赋值为 grid[0][0],还有就是第一行和第一列,其中第一行的位置只能从左边过来,第一列的位置从能从上面过来,所以这两行要提前初始化好,然后再从 (1, 1) 的位置开始更新到右下角即可,反正难度不算大,代码如下:

解法一:

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

我们可以优化空间复杂度,可以使用一个一维的 dp 数组就可以了,初始化为整型最大值,但是 dp[0][0] 要初始化为0。之所以可以用一维数组代替之前的二维数组,是因为当前的 dp 值只跟左边和上面的 dp 值有关。这里我们并不提前更新第一行或是第一列,而是在遍历的时候判断,若j等于0时,说明是第一列,我们直接加上当前的数字,否则就要比较是左边的 dp[j-1] 小还是上面的 dp[j]  小,当是第一行的时候,dp[j] 是整型最大值,所以肯定会取到 dp[j-1] 的值,然后再加上当前位置的数字即可,参见代码如下:

解法二:

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

我们还可以进一步的优化空间,连一维数组都不用新建,而是直接使用原数组 grid 进行累加,这里的累加方式跟解法一稍有不同,没有提前对第一行和第一列进行赋值,而是放在一起判断了,当i和j同时为0时,直接跳过。否则当i等于0时,只加上左边的值,当j等于0时,只加上面的值,否则就比较左边和上面的值,加上较小的那个即可,参见代码如下:

解法三:

class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[].empty()) return ;
for (int i = ; i < grid.size(); ++i) {
for (int j = ; j < grid[i].size(); ++j) {
if (i == && j == ) continue;
if (i == ) grid[][j] += grid[][j - ];
else if (j == ) grid[i][] += grid[i - ][];
else grid[i][j] += min(grid[i - ][j], grid[i][j - ]);
}
}
return grid.back().back();
}
};

下面这种写法跟上面的基本相同,只不过用了 up 和 left 两个变量来计算上面和左边的值,看起来稍稍简洁一点,参见代码如下:

解法四:

class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.empty() || grid[].empty()) return ;
for (int i = ; i < grid.size(); ++i) {
for (int j = ; j < grid[i].size(); ++j) {
if (i == && j == ) continue;
int up = (i == ) ? INT_MAX : grid[i - ][j];
int left = (j == ) ? INT_MAX : grid[i][j - ];
grid[i][j] += min(up, left);
}
}
return grid.back().back();
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/64

类似题目:

Unique Paths

Dungeon Game

Cherry Pickup

参考资料:

https://leetcode.com/problems/minimum-path-sum/

https://leetcode.com/problems/minimum-path-sum/discuss/23457/C%2B%2B-DP

https://leetcode.com/problems/minimum-path-sum/discuss/23617/C%2B%2B-solution-beat-98.59

https://leetcode.com/problems/minimum-path-sum/discuss/23611/My-Java-clean-code-DP-no-extra-space

https://leetcode.com/problems/minimum-path-sum/discuss/23678/C%2B%2B-easy-solution-using-dp.-space-compexity-%3A-O(1)

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 64. Minimum Path Sum 最小路径和的更多相关文章

  1. [leetcode]64. Minimum Path Sum最小路径和

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  2. [LeetCode] Minimum Path Sum 最小路径和

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  3. 64. Minimum Path Sum(最小走棋盘 动态规划)

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  4. LeetCode 64. Minimum Path Sum(最小和的路径)

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  5. LeetCode 64 Minimum Path Sum

    Problem: Given a m x n grid filled with non-negative numbers, find a path from top left to bottom ri ...

  6. 064 Minimum Path Sum 最小路径和

    给定一个只含非负整数的 m x n 网格,找到一条从左上角到右下角的可以使数字之和最小的路径.注意: 每次只能向下或者向右移动一步.示例 1:[[1,3,1], [1,5,1], [4,2,1]]根据 ...

  7. C#解leetcode 64. Minimum Path Sum

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  8. leetCode 64.Minimum Path Sum (最短路) 解题思路和方法

    Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...

  9. Leetcode64.Minimum Path Sum最小路径和

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

随机推荐

  1. git push 报504 (因提交文件内容过大而失败的解决方案)

    Enumerating objects: 60, done. Counting objects: 100% (60/60), done. Delta compression using up to 4 ...

  2. LeetCode 622:设计循环队列 Design Circular Queue

    LeetCode 622:设计循环队列 Design Circular Queue 首先来看看队列这种数据结构: 队列:先入先出的数据结构 在 FIFO 数据结构中,将首先处理添加到队列中的第一个元素 ...

  3. 深圳龙华有轨电车BIM项目

    本项目是“龙华有轨电车BIM+GIS运维管理平台“研发组成的内容之一,包含站台.电车.变电所等模型绘制. 龙华区有轨电车是深圳市的一条位于龙华区的有轨电车线路,项目规划了三条线路,总长51公里.试验线 ...

  4. Reids Lua 模糊查询所有key 及 相对应的集合总数

    Redis 使用 Lua 模糊查询所有key 及 相对应的集合总数 .Net 4.5.1 需要引入:    StackExchange.Redis  (测试用的 1.2.4.0) 方法一: 优点:原子 ...

  5. python 统计使用技巧

    python 统计使用技巧 # 1.不输入回车获取值 注:需要tty模块配合. fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) ...

  6. 【MySQL】多表查询&事务&权限管理

    多表查询: 查询语法: select 列名列表 from 表名列表 where.... 例子: 创建部门表 CREATE TABLE dept( id INT PRIMARY KEY AUTO_INC ...

  7. 搭建rsyslog日志服务器

    环境配置 centos7系统 client1:192.168.91.17 centos7系统 master:192.168.91.18 rsyslog客户端配置 1.rsyslog安装 yum ins ...

  8. flask-script、flask-admin组件

    目录 flask-script 安装 使用 自定制命令 flask-admin 安装 简单使用 将表模型注册到admin中 如果有个字段是图片字段 flask-script 用于实现类似于django ...

  9. HTTPS与HTTP区别

    HTTP + 加密 + 认证 + 完整性保护 = HTTPS http的全称是Hypertext Transfer Protocol Vertion (超文本传输协议) HTTPS: HTTPS(Se ...

  10. Redis入门学习(一):简介

    Redis是一个开源的.高性能的.基于键值对的缓存与存储系统,通过提供多种键值数据类型来适应不同场景下的缓存与存储需求.同时Redis的诸多高层级功能使其可以胜任消息队列.任务队列等不同的角色. 20 ...