@@ -73,17 +73,11 @@ tags:
73
73
我们定义 $f[ i] [ j ] $ 表示从三角形底部走到位置 $(i, j)$ 的最小路径和。这里的位置 $(i, j)$ 指的是三角形中第 $i$ 行第 $j$ 列(均从 0ドル$ 开始编号)的位置。那么我们有如下的状态转移方程:
74
74
75
75
$$
76
- f[i][j] = \min(f[i + 1][j], f[i + 1][j + 1]) + triangle[i][j]
76
+ f[i][j] = \min(f[i + 1][j], f[i + 1][j + 1]) + \text{ triangle} [i][j]
77
77
$$
78
78
79
79
答案即为 $f[ 0] [ 0 ] $。
80
80
81
- 我们注意到,状态 $f[ i] [ j ] $ 仅与状态 $f[ i + 1] [ j ] $ 和状态 $f[ i + 1] [ j + 1 ] $ 有关,因此我们可以使用一维数组代替二维数组,将空间复杂度从 $O(n^2)$ 降低至 $O(n)$。
82
-
83
- 时间复杂度 $O(n^2),ドル空间复杂度 $O(n)$。其中 $n$ 是三角形的行数。
84
-
85
- 更进一步,我们还可以直接复用 $triangle$ 作为 $f$ 数组,这样就无需再额外创建 $f$ 数组,空间复杂度降低至 $O(1)$。
86
-
87
81
<!-- tabs:start -->
88
82
89
83
#### Python3
@@ -105,13 +99,13 @@ class Solution:
105
99
class Solution {
106
100
public int minimumTotal (List<List<Integer > > triangle ) {
107
101
int n = triangle. size();
108
- int [] f = new int [n + 1 ];
102
+ int [][] f = new int [n + 1 ] [n + 1 ];
109
103
for (int i = n - 1 ; i >= 0 ; -- i) {
110
104
for (int j = 0 ; j <= i; ++ j) {
111
- f[j] = Math . min(f[j], f[j + 1 ]) + triangle. get(i). get(j);
105
+ f[i][ j] = Math . min(f[i + 1 ][ j], f[i + 1 ] [j + 1 ]) + triangle. get(i). get(j);
112
106
}
113
107
}
114
- return f[0 ];
108
+ return f[0 ][ 0 ] ;
115
109
}
116
110
}
117
111
```
@@ -123,14 +117,13 @@ class Solution {
123
117
public:
124
118
int minimumTotal(vector<vector<int >>& triangle) {
125
119
int n = triangle.size();
126
- int f[ n + 1] ;
127
- memset(f, 0, sizeof(f));
128
- for (int i = n - 1; ~ i; --i) {
120
+ vector<vector<int >> f(n + 1, vector<int >(n + 1, 0));
121
+ for (int i = n - 1; i >= 0; --i) {
129
122
for (int j = 0; j <= i; ++j) {
130
- f[ j] = min(f[ j] , f[ j + 1] ) + triangle[ i] [ j ] ;
123
+ f[ i ] [ j ] = min(f[ i + 1 ] [ j ] , f[ i + 1 ] [ j + 1 ] ) + triangle[ i] [ j ] ;
131
124
}
132
125
}
133
- return f[ 0] ;
126
+ return f[ 0] [ 0 ] ;
134
127
}
135
128
};
136
129
```
@@ -140,13 +133,16 @@ public:
140
133
```go
141
134
func minimumTotal(triangle [][]int) int {
142
135
n := len(triangle)
143
- f := make([]int, n+1)
136
+ f := make([][]int, n+1)
137
+ for i := range f {
138
+ f[i] = make([]int, n+1)
139
+ }
144
140
for i := n - 1; i >= 0; i-- {
145
141
for j := 0; j <= i; j++ {
146
- f[j] = min(f[j], f[j+1]) + triangle[i][j]
142
+ f[i][ j] = min(f[i+1][ j], f[i+1] [j+1]) + triangle[i][j]
147
143
}
148
144
}
149
- return f[0]
145
+ return f[0][0]
150
146
}
151
147
```
152
148
@@ -155,13 +151,13 @@ func minimumTotal(triangle [][]int) int {
155
151
``` ts
156
152
function minimumTotal(triangle : number [][]): number {
157
153
const n = triangle .length ;
158
- const f: number [] = Array ( n + 1 ) .fill (0 );
159
- for (let i = n - 1 ; ~ i ; -- i ) {
154
+ const f: number [][] = Array . from ({ length: n + 1 }, () => Array ( n + 1 ) .fill (0 ) );
155
+ for (let i = n - 1 ; i >= 0 ; -- i ) {
160
156
for (let j = 0 ; j <= i ; ++ j ) {
161
- f [j ] = Math .min (f [j ], f [j + 1 ]) + triangle [i ][j ];
157
+ f [i ][ j ] = Math .min (f [i + 1 ][ j ], f [ i + 1 ] [j + 1 ]) + triangle [i ][j ];
162
158
}
163
159
}
164
- return f [0 ];
160
+ return f [0 ][ 0 ] ;
165
161
}
166
162
```
167
163
@@ -171,13 +167,13 @@ function minimumTotal(triangle: number[][]): number {
171
167
impl Solution {
172
168
pub fn minimum_total (triangle : Vec <Vec <i32 >>) -> i32 {
173
169
let n = triangle . len ();
174
- let mut f = vec! [0 ; n + 1 ];
170
+ let mut f = vec! [vec! [ 0 ; n + 1 ] ; n + 1 ];
175
171
for i in (0 .. n ). rev () {
176
172
for j in 0 ..= i {
177
- f [j ] = f [j ]. min (f [j + 1 ]) + triangle [i ][j ];
173
+ f [i ][ j ] = f [i + 1 ][ j ]. min (f [ i + 1 ] [j + 1 ]) + triangle [i ][j ];
178
174
}
179
175
}
180
- f [0 ]
176
+ f [0 ][ 0 ]
181
177
}
182
178
}
183
179
```
@@ -188,7 +184,11 @@ impl Solution {
188
184
189
185
<!-- solution: start -->
190
186
191
- ### 方法二
187
+ ### 方法二:动态规划(空间优化)
188
+
189
+ 我们注意到,状态 $f[ i] [ j ] $ 仅与状态 $f[ i + 1] [ j ] $ 和状态 $f[ i + 1] [ j + 1 ] $ 有关,因此我们可以使用一维数组代替二维数组,将空间复杂度从 $O(n^2)$ 降低至 $O(n)$。
190
+
191
+ 时间复杂度 $O(n^2),ドル空间复杂度 $O(n)$。其中 $n$ 是三角形的行数。
192
192
193
193
<!-- tabs: start -->
194
194
@@ -210,14 +210,14 @@ class Solution:
210
210
``` java
211
211
class Solution {
212
212
public int minimumTotal (List<List<Integer > > triangle ) {
213
- for (int i = triangle. size() - 2 ; i >= 0 ; -- i) {
213
+ int n = triangle. size();
214
+ int [] f = new int [n + 1 ];
215
+ for (int i = n - 1 ; i >= 0 ; -- i) {
214
216
for (int j = 0 ; j <= i; ++ j) {
215
- int x = triangle. get(i). get(j);
216
- int y = Math . min(triangle. get(i + 1 ). get(j), triangle. get(i + 1 ). get(j + 1 ));
217
- triangle. get(i). set(j, x + y);
217
+ f[j] = Math . min(f[j], f[j + 1 ]) + triangle. get(i). get(j);
218
218
}
219
219
}
220
- return triangle . get( 0 ) . get( 0 ) ;
220
+ return f[ 0 ] ;
221
221
}
222
222
}
223
223
```
@@ -228,12 +228,14 @@ class Solution {
228
228
class Solution {
229
229
public:
230
230
int minimumTotal(vector<vector<int >>& triangle) {
231
- for (int i = triangle.size() - 2; ~ i; --i) {
231
+ int n = triangle.size();
232
+ vector<int > f(n + 1, 0);
233
+ for (int i = n - 1; i >= 0; --i) {
232
234
for (int j = 0; j <= i; ++j) {
233
- triangle [ i ] [ j ] + = min(triangle [ i + 1 ] [ j ] , triangle [ i + 1] [ j + 1 ] ) ;
235
+ f [ j] = min(f [ j] , f [ j + 1] ) + triangle [ i ] [ j ] ;
234
236
}
235
237
}
236
- return triangle [ 0 ] [ 0 ] ;
238
+ return f [ 0] ;
237
239
}
238
240
};
239
241
```
@@ -242,25 +244,29 @@ public:
242
244
243
245
```go
244
246
func minimumTotal(triangle [][]int) int {
245
- for i := len(triangle) - 2; i >= 0; i-- {
247
+ n := len(triangle)
248
+ f := make([]int, n+1)
249
+ for i := n - 1; i >= 0; i-- {
246
250
for j := 0; j <= i; j++ {
247
- triangle[i][ j] + = min(triangle[i+1][j], triangle[i+1 ][j+1])
251
+ f[ j] = min(f[j], f[j+1]) + triangle[i][j]
248
252
}
249
253
}
250
- return triangle[0] [0]
254
+ return f [0]
251
255
}
252
256
```
253
257
254
258
#### TypeScript
255
259
256
260
``` ts
257
261
function minimumTotal(triangle : number [][]): number {
258
- for (let i = triangle .length - 2 ; ~ i ; -- i ) {
262
+ const n = triangle .length ;
263
+ const f: number [] = Array (n + 1 ).fill (0 );
264
+ for (let i = n - 1 ; i >= 0 ; -- i ) {
259
265
for (let j = 0 ; j <= i ; ++ j ) {
260
- triangle [ i ][ j ] + = Math .min (triangle [ i + 1 ][ j ], triangle [ i + 1 ][ j + 1 ]) ;
266
+ f [ j ] = Math .min (f [ j ], f [ j + 1 ]) + triangle [ i ][ j ] ;
261
267
}
262
268
}
263
- return triangle [ 0 ] [0 ];
269
+ return f [0 ];
264
270
}
265
271
```
266
272
@@ -269,13 +275,14 @@ function minimumTotal(triangle: number[][]): number {
269
275
``` rust
270
276
impl Solution {
271
277
pub fn minimum_total (triangle : Vec <Vec <i32 >>) -> i32 {
272
- let mut triangle = triangle ;
273
- for i in (0 .. triangle . len () - 1 ). rev () {
278
+ let n = triangle . len ();
279
+ let mut f = vec! [0 ; n + 1 ];
280
+ for i in (0 .. n ). rev () {
274
281
for j in 0 ..= i {
275
- triangle [ i ][ j ] += triangle [ i + 1 ][ j ]. min (triangle [ i + 1 ][ j + 1 ]) ;
282
+ f [ j ] = f [ j ]. min (f [ j + 1 ]) + triangle [ i ][ j ] ;
276
283
}
277
284
}
278
- triangle [ 0 ] [0 ]
285
+ f [0 ]
279
286
}
280
287
}
281
288
```
@@ -284,28 +291,4 @@ impl Solution {
284
291
285
292
<!-- solution: end -->
286
293
287
- <!-- solution: start -->
288
-
289
- ### 方法三
290
-
291
- <!-- tabs: start -->
292
-
293
- #### Python3
294
-
295
- ``` python
296
- class Solution :
297
- def minimumTotal (self , triangle : List[List[int ]]) -> int :
298
- n = len (triangle)
299
- for i in range (n - 2 , - 1 , - 1 ):
300
- for j in range (i + 1 ):
301
- triangle[i][j] = (
302
- min (triangle[i + 1 ][j], triangle[i + 1 ][j + 1 ]) + triangle[i][j]
303
- )
304
- return triangle[0 ][0 ]
305
- ```
306
-
307
- <!-- tabs: end -->
308
-
309
- <!-- solution: end -->
310
-
311
294
<!-- problem: end -->
0 commit comments