94 lines
2.3 KiB
Markdown
94 lines
2.3 KiB
Markdown
---
|
|
title: 动态规划(2)
|
|
date: 2018-9-1 21:40:02
|
|
tags:
|
|
- 算法
|
|
- 动态规划
|
|
categories:
|
|
- 算法
|
|
---
|
|
### 最小路径和
|
|
|
|
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
|
|
说明:每次只能向下或者向右移动一步。
|
|
<!-- more -->
|
|
> 示例:
|
|
输入:
|
|
[
|
|
[1,3,1],
|
|
[1,5,1],
|
|
[4,2,1]
|
|
]
|
|
输出: 7
|
|
解释: 因为路径 1→3→1→1→1 的总和最小。
|
|
|
|
这个问题其实和上一篇当中的 **最大子序和** 可以采用相似的方式来解决
|
|
创建一个 m x n 的二维数组
|
|
数组中每个位置记录到达该位置的最小路径和
|
|
到达该位置的最小路径和 = min(到达左侧位置的最小路径和, 到达上方位置的最小路径和) + 给定数组在当前格的值
|
|
同时排除掉第一行和第一列的特殊情况
|
|
|
|
#### 代码实现
|
|
```java
|
|
public int minPathSum(int[][] grid) {
|
|
int m = grid.length;
|
|
if(m == 0) {
|
|
return 0;
|
|
}
|
|
int n = grid[0].length;
|
|
if(n == 0) {
|
|
return 0;
|
|
}
|
|
int[][] nums = new int[m][n];
|
|
nums[0][0] = grid[0][0];
|
|
int currentMin = 0;
|
|
for(int i=0 ; i<m ; i++) {
|
|
for(int j=0 ; j<n ; j++) {
|
|
if(i == 0 && j == 0) {
|
|
continue;
|
|
}
|
|
if(i-1 < 0) {
|
|
currentMin = nums[i][j-1];
|
|
} else if (j-1 < 0) {
|
|
currentMin = nums[i-1][j];
|
|
} else {
|
|
currentMin = Math.min(nums[i][j-1], nums[i-1][j]);
|
|
}
|
|
nums[i][j] = grid[i][j] + currentMin;
|
|
}
|
|
}
|
|
return nums[m-1][n-1];
|
|
}
|
|
```
|
|
时间复杂度是O(mn), 空间复杂度是O(mn)
|
|
当然空间复杂度可以继续优化, 完全可以在传入的数组上面直接对数值进行覆盖, 不去开辟额外的空间
|
|
让空间复杂度达到O(1)
|
|
```java
|
|
public int minPathSum(int[][] grid) {
|
|
int m = grid.length;
|
|
if(m == 0) {
|
|
return 0;
|
|
}
|
|
int n = grid[0].length;
|
|
if(n == 0) {
|
|
return 0;
|
|
}
|
|
int currentMin = 0;
|
|
for(int i=0 ; i<m ; i++) {
|
|
for(int j=0 ; j<n ; j++) {
|
|
if(i == 0 && j == 0) {
|
|
continue;
|
|
}
|
|
if(i-1 < 0) {
|
|
currentMin = grid[i][j-1];
|
|
} else if (j-1 < 0) {
|
|
currentMin = grid[i-1][j];
|
|
} else {
|
|
currentMin = Math.min(grid[i][j-1], grid[i-1][j]);
|
|
}
|
|
grid[i][j] = grid[i][j] + currentMin;
|
|
}
|
|
}
|
|
return grid[m-1][n-1];
|
|
}
|
|
``` |