LeetCode 64 最小路径和
题目描述
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每一次只能向下或者向右移动一步。
示例
输入:[[1, 3, 1], [1, 5, 1], [4, 2, 1]]
输出:7
解释:1->3->1->1->1的总和最小为7
题目解析
有了求三角形最短路径和的经验,该题求在长方体中的最短路径和的思路也是类似的。也是采用动态规划的思想,将问题划分为更小规模的问题进行求解。具体思路如下:
-
既然是采用动态规划的方式求解,首先要做的就是找出其递推方程,下面先使用图示来模拟出程序可能出现的每一个结果,以此推导出我们要的递推方程。
-
创建一个dp[n]的数组,用来保存每一行中到达每一个格子的最短路径。这里没有创建一个和输入一样大小的二维数组同样是使用到了“滚动数组”的概念,即重复的对该数组的值重新赋值。
-
计算第一行每一个格子的数据。由于第一行中的格子只能由其右边格子走到,因此计算结果如下:用dp数组中数据来替换格子中的数据,此时dp = {1, 4, 5};
-
- 计算接下去中每个格子的数据,其中由于第一格子的路径和只能由其上面格子的得到,因此可以提前计算出来,即是累加起来。
对于接下去的格子,它可能是由其左边和上边格子得来,这个时候就要比较这两种走法路径和哪个最下了。如下:可以结合上图来看。
其最短路径路线即如下图:
上述每一行的数据变化都是指dp数组中数据的变化。
-
通过模拟一遍就可以发现地递推的一个过程了
首先,第一行中的数据可以采用如下递推式:
dp[i] = dp[i - 1] + grid[0] [j];
接着,下面每一行的第一数据可以采用如下递推式:
dp[0] = dp[0] + grid[i] [0];
其他格子的递推式如下:
dp[j] = Math.min(dp[j], dp[j - 1]) + grid[i][j];
最后将dp[n - 1]返回即是我们想要的答案。
程序实现
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[] dp = new int[n];
dp[0] = grid[0][0];
for (int i = 1; i < n; i++) {
dp[i] = grid[0][i] + dp[i - 1];
}
for (int i = 1; i < m; i++) {
dp[0] = dp[0] + grid[i][0];
for (int j = 1; j < n; j++) {
dp[j] = Math.min(dp[j], dp[j - 1]) + grid[i][j];
}
}
return dp[n - 1];
}
}
程序运行结果
时间复杂度为:O(n^2)
空间复杂度为:O(n)
PS: 不知是有了一些写动态规划题目的经验还是题目比较简单,现在看到类似的题目不再像以前看到动态规划的名称就发慌,不管怎么样还是得多练咯~