@@ -73,17 +73,11 @@ tags:
7373我们定义 $f[ i] [ j ] $ 表示从三角形底部走到位置 $(i, j)$ 的最小路径和。这里的位置 $(i, j)$ 指的是三角形中第 $i$ 行第 $j$ 列(均从 $0$ 开始编号)的位置。那么我们有如下的状态转移方程:
7474
7575$$
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]
7777$$
7878
7979答案即为 $f[ 0] [ 0 ] $。
8080
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-
8781<!-- tabs:start -->
8882
8983#### Python3
@@ -105,13 +99,13 @@ class Solution:
10599class Solution {
106100 public int minimumTotal (List<List<Integer > > triangle ) {
107101 int n = triangle. size();
108- int [] f = new int [n + 1 ];
102+ int [][] f = new int [n + 1 ] [n + 1 ];
109103 for (int i = n - 1 ; i >= 0 ; -- i) {
110104 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);
112106 }
113107 }
114- return f[0 ];
108+ return f[0 ][ 0 ] ;
115109 }
116110}
117111```
@@ -123,14 +117,13 @@ class Solution {
123117public:
124118 int minimumTotal(vector<vector<int >>& triangle) {
125119 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) {
129122 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 ] ;
131124 }
132125 }
133- return f[ 0] ;
126+ return f[ 0] [ 0 ] ;
134127 }
135128};
136129```
@@ -140,13 +133,16 @@ public:
140133```go
141134func minimumTotal(triangle [][]int) int {
142135 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+ }
144140 for i := n - 1; i >= 0; i-- {
145141 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]
147143 }
148144 }
149- return f[0]
145+ return f[0][0]
150146}
151147```
152148
@@ -155,13 +151,13 @@ func minimumTotal(triangle [][]int) int {
155151``` ts
156152function minimumTotal(triangle : number [][]): number {
157153 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 ) {
160156 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 ];
162158 }
163159 }
164- return f [0 ];
160+ return f [0 ][ 0 ] ;
165161}
166162```
167163
@@ -171,13 +167,13 @@ function minimumTotal(triangle: number[][]): number {
171167impl Solution {
172168 pub fn minimum_total (triangle : Vec <Vec <i32 >>) -> i32 {
173169 let n = triangle . len ();
174- let mut f = vec! [0 ; n + 1 ];
170+ let mut f = vec! [vec! [ 0 ; n + 1 ] ; n + 1 ];
175171 for i in (0 .. n ). rev () {
176172 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 ];
178174 }
179175 }
180- f [0 ]
176+ f [0 ][ 0 ]
181177 }
182178}
183179```
@@ -188,7 +184,11 @@ impl Solution {
188184
189185<!-- solution: start -->
190186
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$ 是三角形的行数。
192192
193193<!-- tabs: start -->
194194
@@ -210,14 +210,14 @@ class Solution:
210210``` java
211211class Solution {
212212 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) {
214216 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);
218218 }
219219 }
220- return triangle . get( 0 ) . get( 0 ) ;
220+ return f[ 0 ] ;
221221 }
222222}
223223```
@@ -228,12 +228,14 @@ class Solution {
228228class Solution {
229229public:
230230 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) {
232234 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 ] ;
234236 }
235237 }
236- return triangle [ 0 ] [ 0 ] ;
238+ return f [ 0] ;
237239 }
238240};
239241```
@@ -242,25 +244,29 @@ public:
242244
243245```go
244246func 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-- {
246250 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]
248252 }
249253 }
250- return triangle[0] [0]
254+ return f [0]
251255}
252256```
253257
254258#### TypeScript
255259
256260``` ts
257261function 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 ) {
259265 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 ] ;
261267 }
262268 }
263- return triangle [ 0 ] [0 ];
269+ return f [0 ];
264270}
265271```
266272
@@ -269,13 +275,14 @@ function minimumTotal(triangle: number[][]): number {
269275``` rust
270276impl Solution {
271277 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 () {
274281 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 ] ;
276283 }
277284 }
278- triangle [ 0 ] [0 ]
285+ f [0 ]
279286 }
280287}
281288```
@@ -284,28 +291,4 @@ impl Solution {
284291
285292<!-- solution: end -->
286293
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-
311294<!-- problem: end -->
0 commit comments