@@ -65,7 +65,177 @@ tags:
65
65
66
66
<!-- solution:start -->
67
67
68
- ### 方法一:动态规划
68
+ ### 方法一:记忆化搜索
69
+
70
+ 我们设计一个函数 $textit{dfs}(i)$,表示从第 $i$ 个阶梯开始爬楼梯所需要的最小花费。那么答案为 $\min(\textit{dfs}(0), \textit{dfs}(1))$。
71
+
72
+ 函数 $\textit{dfs}(i)$ 的执行过程如下:
73
+
74
+ - 如果 $i \ge \textit{len(cost)}$,表示当前位置已经超过了楼梯顶部,不需要再爬楼梯,返回 $0$;
75
+ - 否则,我们可以选择爬 $1$ 级楼梯,花费为 $\textit{cost}[ i] $,然后递归调用 $\textit{dfs}(i + 1)$;也可以选择爬 $2$ 级楼梯,花费为 $\textit{cost}[ i] $,然后递归调用 $\textit{dfs}(i + 2)$;
76
+ - 返回两种方案中的最小花费。
77
+
78
+ 为了避免重复计算,我们使用记忆化搜索的方法,将已经计算过的结果保存在数组或哈希表中。
79
+
80
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{cost}$ 的长度。
81
+
82
+ <!-- tabs:start -->
83
+
84
+ #### Python3
85
+
86
+ ``` python
87
+ class Solution :
88
+ def minCostClimbingStairs (self , cost : List[int ]) -> int :
89
+ @cache
90
+ def dfs (i : int ) -> int :
91
+ if i >= len (cost):
92
+ return 0
93
+ return cost[i] + min (dfs(i + 1 ), dfs(i + 2 ))
94
+
95
+ return min (dfs(0 ), dfs(1 ))
96
+ ```
97
+
98
+ #### Java
99
+
100
+ ``` java
101
+ class Solution {
102
+ private Integer [] f;
103
+ private int [] cost;
104
+
105
+ public int minCostClimbingStairs (int [] cost ) {
106
+ this . cost = cost;
107
+ f = new Integer [cost. length];
108
+ return Math . min(dfs(0 ), dfs(1 ));
109
+ }
110
+
111
+ private int dfs (int i ) {
112
+ if (i >= cost. length) {
113
+ return 0 ;
114
+ }
115
+ if (f[i] == null ) {
116
+ f[i] = cost[i] + Math . min(dfs(i + 1 ), dfs(i + 2 ));
117
+ }
118
+ return f[i];
119
+ }
120
+ }
121
+ ```
122
+
123
+ #### C++
124
+
125
+ ``` cpp
126
+ class Solution {
127
+ public:
128
+ int minCostClimbingStairs(vector<int >& cost) {
129
+ int n = cost.size();
130
+ int f[ n] ;
131
+ memset(f, -1, sizeof(f));
132
+ auto dfs = [ &] (auto&& dfs, int i) -> int {
133
+ if (i >= n) {
134
+ return 0;
135
+ }
136
+ if (f[ i] < 0) {
137
+ f[ i] = cost[ i] + min(dfs(dfs, i + 1), dfs(dfs, i + 2));
138
+ }
139
+ return f[ i] ;
140
+ };
141
+ return min(dfs(dfs, 0), dfs(dfs, 1));
142
+ }
143
+ };
144
+ ```
145
+
146
+ #### Go
147
+
148
+ ```go
149
+ func minCostClimbingStairs(cost []int) int {
150
+ n := len(cost)
151
+ f := make([]int, n)
152
+ for i := range f {
153
+ f[i] = -1
154
+ }
155
+ var dfs func(int) int
156
+ dfs = func(i int) int {
157
+ if i >= n {
158
+ return 0
159
+ }
160
+ if f[i] < 0 {
161
+ f[i] = cost[i] + min(dfs(i+1), dfs(i+2))
162
+ }
163
+ return f[i]
164
+ }
165
+ return min(dfs(0), dfs(1))
166
+ }
167
+ ```
168
+
169
+ #### TypeScript
170
+
171
+ ``` ts
172
+ function minCostClimbingStairs(cost : number []): number {
173
+ const n = cost .length ;
174
+ const f: number [] = Array (n ).fill (- 1 );
175
+ const dfs = (i : number ): number => {
176
+ if (i >= n ) {
177
+ return 0 ;
178
+ }
179
+ if (f [i ] < 0 ) {
180
+ f [i ] = cost [i ] + Math .min (dfs (i + 1 ), dfs (i + 2 ));
181
+ }
182
+ return f [i ];
183
+ };
184
+ return Math .min (dfs (0 ), dfs (1 ));
185
+ }
186
+ ```
187
+
188
+ #### Rust
189
+
190
+ ``` rust
191
+ impl Solution {
192
+ pub fn min_cost_climbing_stairs (cost : Vec <i32 >) -> i32 {
193
+ let n = cost . len ();
194
+ let mut f = vec! [- 1 ; n ];
195
+
196
+ fn dfs (i : usize , cost : & Vec <i32 >, f : & mut Vec <i32 >, n : usize ) -> i32 {
197
+ if i >= n {
198
+ return 0 ;
199
+ }
200
+ if f [i ] < 0 {
201
+ let next1 = dfs (i + 1 , cost , f , n );
202
+ let next2 = dfs (i + 2 , cost , f , n );
203
+ f [i ] = cost [i ] + next1 . min (next2 );
204
+ }
205
+ f [i ]
206
+ }
207
+
208
+ dfs (0 , & cost , & mut f , n ). min (dfs (1 , & cost , & mut f , n ))
209
+ }
210
+ }
211
+ ```
212
+
213
+ #### JavaScript
214
+
215
+ ``` js
216
+ function minCostClimbingStairs (cost ) {
217
+ const n = cost .length ;
218
+ const f = Array (n).fill (- 1 );
219
+ const dfs = i => {
220
+ if (i >= n) {
221
+ return 0 ;
222
+ }
223
+ if (f[i] < 0 ) {
224
+ f[i] = cost[i] + Math .min (dfs (i + 1 ), dfs (i + 2 ));
225
+ }
226
+ return f[i];
227
+ };
228
+ return Math .min (dfs (0 ), dfs (1 ));
229
+ }
230
+ ```
231
+
232
+ <!-- tab: end -->
233
+
234
+ <!-- solution: end -->
235
+
236
+ <!-- solution: start -->
237
+
238
+ ### 方法二:动态规划
69
239
70
240
我们定义 $f[ i] $ 表示到达第 $i$ 个阶梯所需要的最小花费,初始时 $f[ 0] = f[ 1] = 0$,答案即为 $f[ n] $。
71
241
77
247
78
248
最终的答案即为 $f[ n] $。
79
249
80
- 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 ` cost ` 的长度。
81
-
82
- 我们注意到,状态转移方程中的 $f[ i] $ 只和 $f[ i - 1] $ 与 $f[ i - 2] $ 有关,因此我们可以使用两个变量 $f$ 和 $g$ 交替地记录 $f[ i - 2] $ 和 $f[ i - 1] $ 的值,这样空间复杂度可以优化到 $O(1)$。
250
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{cost}$ 的长度。
83
251
84
252
<!-- tabs: start -->
85
253
@@ -152,19 +320,6 @@ function minCostClimbingStairs(cost: number[]): number {
152
320
}
153
321
```
154
322
155
- #### JavaScript
156
-
157
- ``` js
158
- function minCostClimbingStairs (cost ) {
159
- const n = cost .length ;
160
- const f = Array (n + 1 ).fill (0 );
161
- for (let i = 2 ; i <= n; ++ i) {
162
- f[i] = Math .min (f[i - 1 ] + cost[i - 1 ], f[i - 2 ] + cost[i - 2 ]);
163
- }
164
- return f[n];
165
- }
166
- ```
167
-
168
323
#### Rust
169
324
170
325
``` rust
@@ -180,13 +335,28 @@ impl Solution {
180
335
}
181
336
```
182
337
338
+ #### JavaScript
339
+
340
+ ``` js
341
+ function minCostClimbingStairs (cost ) {
342
+ const n = cost .length ;
343
+ const f = Array (n + 1 ).fill (0 );
344
+ for (let i = 2 ; i <= n; ++ i) {
345
+ f[i] = Math .min (f[i - 1 ] + cost[i - 1 ], f[i - 2 ] + cost[i - 2 ]);
346
+ }
347
+ return f[n];
348
+ }
349
+ ```
350
+
183
351
<!-- tabs: end -->
184
352
185
353
<!-- solution: end -->
186
354
187
355
<!-- solution: start -->
188
356
189
- ### 方法二
357
+ ### 方法三:动态规划(空间优化)
358
+
359
+ 我们注意到,状态转移方程中的 $f[ i] $ 只和 $f[ i - 1] $ 与 $f[ i - 2] $ 有关,因此我们可以使用两个变量 $f$ 和 $g$ 交替地记录 $f[ i - 2] $ 和 $f[ i - 1] $ 的值,这样空间复杂度可以优化到 $O(1)$。
190
360
191
361
<!-- tabs: start -->
192
362
@@ -250,25 +420,11 @@ func minCostClimbingStairs(cost []int) int {
250
420
251
421
``` ts
252
422
function minCostClimbingStairs(cost : number []): number {
253
- let a = 0 ,
254
- b = 0 ;
423
+ let [f, g] = [0 , 0 ];
255
424
for (let i = 1 ; i < cost .length ; ++ i ) {
256
- [a , b ] = [b , Math .min (a + cost [i - 1 ], b + cost [i ])];
425
+ [f , g ] = [g , Math .min (f + cost [i - 1 ], g + cost [i ])];
257
426
}
258
- return b ;
259
- }
260
- ```
261
-
262
- #### JavaScript
263
-
264
- ``` js
265
- function minCostClimbingStairs (cost ) {
266
- let a = 0 ,
267
- b = 0 ;
268
- for (let i = 1 ; i < cost .length ; ++ i) {
269
- [a, b] = [b, Math .min (a + cost[i - 1 ], b + cost[i])];
270
- }
271
- return b;
427
+ return g ;
272
428
}
273
429
```
274
430
@@ -288,53 +444,15 @@ impl Solution {
288
444
}
289
445
```
290
446
291
- <!-- tabs: end -->
292
-
293
- <!-- solution: end -->
294
-
295
- <!-- solution: start -->
296
-
297
- ### Solution 3: Dynamic Programming. Recursion and top-down approach
298
-
299
- <!-- tabs: start -->
300
-
301
- #### TypeScript
302
-
303
- ``` ts
304
- function minCostClimbingStairs(cost : number []): number {
305
- const n = cost .length ;
306
- const cache = Array (n ).fill (- 1 );
307
-
308
- const fn = (i : number ): number => {
309
- if (i <= 1 ) return cost [i ];
310
- if (cache [i ] !== undefined && cache [i ] !== - 1 ) return cache [i ];
311
-
312
- cache [i ] = (cost [i ] ?? 0 ) + Math .min (fn (i - 1 ), fn (i - 2 ));
313
-
314
- return cache [i ];
315
- };
316
-
317
- return fn (n );
318
- }
319
- ```
320
-
321
447
#### JavaScript
322
448
323
449
``` js
324
450
function minCostClimbingStairs (cost ) {
325
- const n = cost .length ;
326
- const cache = Array (n).fill (- 1 );
327
-
328
- const fn = i => {
329
- if (i <= 1 ) return cost[i];
330
- if (cache[i] !== undefined && cache[i] !== - 1 ) return cache[i];
331
-
332
- cache[i] = (cost[i] ?? 0 ) + Math .min (fn (i - 1 ), fn (i - 2 ));
333
-
334
- return cache[i];
335
- };
336
-
337
- return fn (n);
451
+ let [f, g] = [0 , 0 ];
452
+ for (let i = 1 ; i < cost .length ; ++ i) {
453
+ [f, g] = [g, Math .min (f + cost[i - 1 ], g + cost[i])];
454
+ }
455
+ return g;
338
456
}
339
457
```
340
458
0 commit comments