[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 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
类似题目:
参考资料:
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
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Minimum Path Sum 最小路径和的更多相关文章
- [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 ...
- [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 ...
- 064 Minimum Path Sum 最小路径和
给定一个只含非负整数的 m x n 网格,找到一条从左上角到右下角的可以使数字之和最小的路径.注意: 每次只能向下或者向右移动一步.示例 1:[[1,3,1], [1,5,1], [4,2,1]]根据 ...
- Leetcode64.Minimum Path Sum最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入: [ [1,3,1], [1,5,1] ...
- [LeetCode] 113. Path Sum II 路径和 II
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given su ...
- [LeetCode] 437. Path Sum III 路径和 III
You are given a binary tree in which each node contains an integer value. Find the number of paths t ...
- LeetCode: Minimum Path Sum 解题报告
Minimum Path Sum Given a m x n grid filled with non-negative numbers, find a path from top left to b ...
- 动态规划小结 - 二维动态规划 - 时间复杂度 O(n*n)的棋盘型,题 [LeetCode] Minimum Path Sum,Unique Paths II,Edit Distance
引言 二维动态规划中最常见的是棋盘型二维动态规划. 即 func(i, j) 往往只和 func(i-1, j-1), func(i-1, j) 以及 func(i, j-1) 有关 这种情况下,时间 ...
- LeetCode:Minimum Path Sum(网格最大路径和)
题目链接 Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right ...
随机推荐
- 浏览器加载和渲染HTML的过程(标准定义的过程以及现代浏览器的优化)
先看一下标准定义的浏览器渲染过程(网上找的): 浏览器打开网页的过程 用户第一次访问网址,浏览器向服务器发出请求,服务器返回html文件: 浏览器开始载入html代码,发现 head 标签内有一个 l ...
- css3新单位学习
vw,vh,vmin,vmax vw 1vw = 视窗width*1% vh 1vh = 视窗heihgt*1% 如果视窗的宽度小于高度,1vmin = 1vw,如果视窗宽度大于高度,1vmin = ...
- 你所不知道的linq
问题的提出 昨天在qq群问了一个linq的问题被人鄙视了.题目大概类似于 var reuslt=from s in new List<string>() select s; 问from.. ...
- 数据仓库开发——Kettle使用示例
Kettle是一个开园ETL工具,做数据仓库用Spoon. 工具:下载Spoon,解压即可用 1.认识常用组件: 表输入 插入\更新 数据同步 文本文件输出 ...
- Web前端资源汇总
本文地址:http://www.cnblogs.com/jihua/p/webfront.html 网页特效库 2017新年快乐特效 CSS3+jQuery实现时钟插件 Html5入门实例" ...
- Date小技巧:set相关操作及应用_获取当前月(季度/年)的最后一天
set操作还是有不少的,具体见 http://www.w3school.com.cn/jsref/jsref_obj_date.asp, 今天我就只说 setFullYear, setMonth, s ...
- Resharper让我们的asp.net开发效率提高三分之一
ReSharper是一个JetBrains公司出品的著名的代码生成工具,其能帮助Microsoft Visual Studio成为一个更佳的IDE.它包括一系列丰富的能大大增加C#和Visual Ba ...
- 在SharePoint 2013 之中使用JS从Add-in程序中读取用户配置文件的属性
经过无数次的实验,只有这个程序可以运行正常 ,代码贴出来纯的JSOM,在我的实验环境老是返回未知错误,为了这一个简单的任务,我已经搞了2天了,不过终于搞出来了,使用各种方法后,还有使用代码. func ...
- RunLoop 总结:RunLoop的应用场景(二)
上一篇讲了使用RunLoop保证子线程的长时间存活,而不是执行完任务后就立刻销毁的应用场景.这一篇就讲述一下RunLoop如何保证NSTimer在视图滑动时,依然能正常运转. 参考资料 好的书籍都是值 ...
- java实现敏感词过滤(DFA算法)
小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxo ...