Skip to content

Commit 315ff8d

Browse files
committed
120
1 parent f76610e commit 315ff8d

File tree

3 files changed

+150
-3
lines changed

3 files changed

+150
-3
lines changed

SUMMARY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
* [99. Recover Binary Search Tree](leetcode-99-Recover-Binary-Search-Tree.md)
103103
* [100. Same Tree](leetcode-100-Same-Tree.md)
104104
* [leetcode 100 斩!回顾](leetcode100斩回顾.md)
105-
* [101 题到 119](leetcode-101-200.md)
105+
* [101 题到 120](leetcode-101-200.md)
106106
* [101. Symmetric Tree](leetcode-101-Symmetric-Tree.md)
107107
* [102. Binary Tree Level Order Traversal](leetcode-102-Binary-Tree-Level-Order-Traversal.md)
108108
* [103. Binary Tree Zigzag Level Order Traversal](leetcode-103-Binary-Tree-Zigzag-Level-Order-Traversal.md)
@@ -121,4 +121,5 @@
121121
* [116. Populating Next Right Pointers in Each Node](leetcode-116-Populating-Next-Right-Pointers-in-Each-Node.md)
122122
* [117. Populating Next Right Pointers in Each Node II](leetcode-117-Populating-Next-Right-Pointers-in-Each-NodeII.md)
123123
* [118. Pascal's Triangle](leetcode-118-Pascal's-Triangle.md)
124-
* [119. Pascal's Triangle II](leetcode-119-Pascal's-TriangleII.md)
124+
* [119. Pascal's Triangle II](leetcode-119-Pascal's-TriangleII.md)
125+
* [120. Triangle](leetcode-120-Triangle.md)

leetcode-101-200.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@
3434

3535
<a href="leetcode-118-Pascal's-Triangle.html">118. Pascal's Triangle</a>
3636

37-
<a href="leetcode-119-Pascal's-TriangleII.html">119. Pascal's Triangle II</a>
37+
<a href="leetcode-119-Pascal's-TriangleII.html">119. Pascal's Triangle II</a>
38+
39+
<a href="leetcode-120-Triangle.html">120. Triangle</a>

leetcode-120-Triangle.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/120.jpg)
4+
5+
当前层只能选择下一层相邻的两个元素走,比如第 `3` 层的 `5` 只能选择第`4`层的 `1``8` ,从最上边开始,走一条路径,走到最底层最小的和是多少。
6+
7+
# 题目解析
8+
9+
先看一下 [115 题](<https://leetcode.wang/leetcode-115-Distinct-Subsequences.html>) 吧,和这道题思路方法是完全完全一样的。此外,[119 题](<https://leetcode.wang/leetcode-119-Pascal%27s-TriangleII.html>) 倒着循环优化空间复杂度也可以看一下。
10+
11+
这道题本质上就是动态规划,再本质一些就是更新一张二维表。
12+
13+
[115 题](<https://leetcode.wang/leetcode-115-Distinct-Subsequences.html>) 已经进行了详细介绍,这里就粗略的记录了。
14+
15+
# 解法一 递归之分支
16+
17+
求第 `0` 层到第 `n` 层的和最小,就是第`0`层的数字加上第`1`层到第`n`层的的最小和。
18+
19+
递归出口就是,第`n`层到第`n`层最小的和,就是该层的数字本身。
20+
21+
```java
22+
public int minimumTotal(List<List<Integer>> triangle) {
23+
return minimumTotalHelper(0, 0, triangle);
24+
}
25+
26+
private int minimumTotalHelper(int row, int col, List<List<Integer>> triangle) {
27+
if (row == triangle.size()) {
28+
return 0;
29+
}
30+
int min = Integer.MAX_VALUE;
31+
List<Integer> cur = triangle.get(row);
32+
min = Math.min(min, cur.get(col) + minimumTotalHelper(row + 1, col, triangle));
33+
if (col + 1 < cur.size()) {
34+
min = Math.min(min, cur.get(col + 1) + minimumTotalHelper(row + 1, col + 1, triangle));
35+
}
36+
return min;
37+
}
38+
```
39+
40+
因为函数里边调用了两次自己,所以导致进行了很多重复的搜索,所以肯定会导致超时。
41+
42+
![](https://windliang.oss-cn-beijing.aliyuncs.com/120_2.jpg)
43+
44+
优化的话,就是 `Memoization` 技术,把每次的结果存起来,进入递归前先判断当前解有没有求出来。我们可以用 `HashMap` 存,也可以用二维数组存。
45+
46+
`HashMap` 的话,`key` 存字符串 `row + "@" + col`,中间之所以加一个分隔符,就是防止`row = 1,col = 23``row = 12, col = 3`,这两种情况的混淆。
47+
48+
```java
49+
public int minimumTotal(List<List<Integer>> triangle) {
50+
HashMap<String, Integer> map = new HashMap<>();
51+
return minimumTotalHelper(0, 0, triangle, map);
52+
}
53+
54+
private int minimumTotalHelper(int row, int col, List<List<Integer>> triangle, HashMap<String, Integer> map) {
55+
if (row == triangle.size()) {
56+
return 0;
57+
}
58+
String key = row + "@" + col;
59+
if (map.containsKey(key)) {
60+
return map.get(key);
61+
}
62+
int min = Integer.MAX_VALUE;
63+
List<Integer> cur = triangle.get(row);
64+
min = Math.min(min, cur.get(col) + minimumTotalHelper(row + 1, col, triangle, map));
65+
if (col + 1 < cur.size()) {
66+
min = Math.min(min, cur.get(col + 1) + minimumTotalHelper(row + 1, col + 1, triangle, map));
67+
}
68+
map.put(key, min);
69+
return min;
70+
}
71+
```
72+
73+
# 动态规划
74+
75+
动态规划可以自顶向下,也可以自底向上, [115 题](<https://leetcode.wang/leetcode-115-Distinct-Subsequences.html>) 主要写的是自底向上,这里写个自顶向下吧。
76+
77+
用一个数组 `dp[row][col]` 表示从顶部到当前位置,即第 `row` 行第 `col` 列,的最小和。
78+
79+
状态转移方程也很好写了。
80+
81+
`dp[row][col] = Min(dp[row - 1][col - 1],dp[row-1][col]), triangle[row][col] `
82+
83+
到当前位置有两种选择,选一个较小的,然后加上当前位置的数字即可。
84+
85+
```java
86+
public int minimumTotal(List<List<Integer>> triangle) {
87+
int rows = triangle.size();
88+
int cols = triangle.get(rows - 1).size();
89+
int[][] dp = new int[rows][cols];
90+
dp[0][0] = triangle.get(0).get(0);
91+
for (int row = 1; row < rows; row++) {
92+
List<Integer> curRow = triangle.get(row);
93+
int col = 0;
94+
dp[row][col] = dp[row - 1][col] + curRow.get(col);
95+
col++;
96+
for (; col < curRow.size() - 1; col++) {
97+
dp[row][col] = Math.min(dp[row - 1][col - 1], dp[row - 1][col]) + curRow.get(col);
98+
}
99+
dp[row][col] = dp[row - 1][col - 1] + curRow.get(col);
100+
}
101+
int min = Integer.MAX_VALUE;
102+
for (int col = 0; col < cols; col++) {
103+
min = Math.min(min, dp[rows - 1][col]);
104+
}
105+
return min;
106+
}
107+
```
108+
109+
注意的地方就是把左边界和右边界的情况单独考虑,因为到达左边界和右边界只有一个位置可选。
110+
111+
接下来,注意到我们是一层一层的更新,更新当前层只需要上一层的信息,所以我们不需要二维数组,只需要一维数组就可以了。
112+
113+
另外,和 [119 题](<https://leetcode.wang/leetcode-119-Pascal%27s-TriangleII.html>) 题一样,更新`col`列的时候,会把之前`col`列的信息覆盖。当更新 `col + 1` 列的时候,旧的 `col` 列的信息已经没有了,所以我们可以采取倒着更新 `col` 的方法。
114+
115+
```java
116+
public int minimumTotal(List<List<Integer>> triangle) {
117+
int rows = triangle.size();
118+
int cols = triangle.get(rows - 1).size();
119+
int[] dp = new int[cols];
120+
dp[0] = triangle.get(0).get(0);
121+
for (int row = 1; row < rows; row++) {
122+
List<Integer> curRow = triangle.get(row);
123+
int col = curRow.size() - 1;
124+
dp[col] = dp[col - 1] + curRow.get(col);
125+
col--;
126+
for (; col > 0; col--) {
127+
dp[col] = Math.min(dp[col - 1], dp[col]) + curRow.get(col);
128+
}
129+
130+
dp[col] = dp[col] + curRow.get(col);
131+
}
132+
int min = Integer.MAX_VALUE;
133+
for (int col = 0; col < cols; col++) {
134+
min = Math.min(min, dp[col]);
135+
}
136+
return min;
137+
}
138+
```
139+
140+
另外,大家可以试一试自底向上的方法,写起来还相对简单些。
141+
142+
#
143+
144+
就是 [115 题](<https://leetcode.wang/leetcode-115-Distinct-Subsequences.html>) 的变形了,没有新东西,如果理解了 [115 题](<https://leetcode.wang/leetcode-115-Distinct-Subsequences.html>) ,那么这道题直接套算法就行,基本不用思考了。

0 commit comments

Comments
 (0)