-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy path64. Minimum Path Sum.java
executable file
·161 lines (140 loc) · 5.56 KB
/
64. Minimum Path Sum.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
M
tags: Array, DP, Coordinate DP
time: O(mn)
space: O(n) rolling array
#### DP
- Time, Space O(MN)
- 往右下角走, 计算最短的 path sum. 典型的坐标型.
- 注意: init 第一行的时候, 要accumulate dp[0][j - 1] + grid[i][j], 而不是单纯assign grid[i][j]
- Rolling Array
- Time O(MN), Space O(N)
- 1) 需要在同一个for loop里面完成initialization, 2) reuse dp[i][j]
- Reason: dp[i % 2][j] 在被计算出来的时候, 马上在下一轮会被用. 被覆盖前不用,就白算
- Option3 below initialize dp outside of loop: 看起来固然简单, 但是不方便空间优化
#### DFS (top-down) Thinking process
- Enumerate the possible 2 paths: go right, go down
- sub problem: dfs(i+1,j), dfs(i,j+1); pick the min of the two
- memoization: after the path from a point (i,j) to end is computed, record memo[i][j] to avoid repatative calculation
- time: O(mn), only visite and record memo[i][j] once.
- space: O(mn) extrem case of m=100000, n = 2; the stack height is O(mn)
```
/*
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
Tags Expand
Dynamic Programming
*/
/*
Thoughts:
Can only move down/right, means at any (i, j), the path comes from top/left.
say dp[i][j] is the min path sum,
so dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]
init:
dp[0][0] = grid[0][0]
dp[0 ~ m][0] and dp[0][0 ~ n] should be accumulated for all [0, 0~n], [0 ~ m, 0]
*/
// Option1: inline use `Integer.MAX_VALUE` to handle `i==0` or `j==0` cases
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0;
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = grid[i][j]; // Initialize
if (i == 0 && j == 0) continue; // skip starting point
// Calculate DP
int fromUp = i == 0 ? Integer.MAX_VALUE : dp[i - 1][j];
int fromLeft = j == 0 ? Integer.MAX_VALUE : dp[i][j - 1];
dp[i][j] += Math.min(fromUp, fromLeft);
}
}
return dp[m - 1][n - 1];
}
}
// Rolling array
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[2][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// Initialize
if (i == 0 && j == 0) {
dp[i % 2][j] = grid[i][j];
continue;
}
// Calculate DP
int fromUp = i == 0 ? Integer.MAX_VALUE : dp[(i - 1) % 2][j];
int fromLeft = j == 0 ? Integer.MAX_VALUE : dp[i % 2][j - 1];
dp[i % 2][j] = Math.min(fromUp, fromLeft) + grid[i][j];
}
}
return dp[(m - 1) % 2][n - 1];
}
}
// Optional2: Not optimal code, but can be optimized with rolling array
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0;
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = grid[i][j]; // Initialize
if (i == 0 && j == 0) continue;
if (i == 0 && j > 0) dp[i][j] += dp[i][j - 1];
else if (i > 0 && j == 0) dp[i][j] += dp[i - 1][j];
else dp[i][j] += Math.min(dp[i - 1][j], dp[i][j - 1]); // Calculate DP
}
}
return dp[m - 1][n - 1];
}
}
// Optional2: Rolling array, space: O(n)
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0;
int m = grid.length, n = grid[0].length;
int[][] dp = new int[2][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[i%2][j] = grid[i][j]; // Initialize
if (i == 0 && j == 0) continue;
if (i == 0 && j > 0) dp[i%2][j] += dp[i%2][j - 1];
else if (i > 0 && j == 0) dp[i%2][j] += dp[(i - 1)%2][j];
else dp[i%2][j] += Math.min(dp[(i - 1)%2][j], dp[i%2][j - 1]); // Calculate DP
}
}
return dp[(m - 1)%2][n - 1];
}
}
// Optoin3: init the 1st row, 1st col outside: cannot do rolling array
class Solution {
public int minPathSum(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
// init:
for (int i = 1; i < m; i++) dp[i][0] = dp[i - 1][0] + grid[i][0];
for (int j = 1; j < n; j++) dp[0][j] = dp[0][j - 1] + grid[0][j];
// calculate
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[m - 1][n - 1];
}
}
```