@@ -55,7 +55,174 @@ tags:
55
55
56
56
<!-- solution:start -->
57
57
58
- ### 方法一:动态规划
58
+ ### 方法一:记忆化搜索
59
+
60
+ 我们设计一个函数 $\textit{dfs}(i)$,表示从第 $i$ 间房屋开始偷窃能够得到的最高金额。那么答案即为 $\textit{dfs}(0)$。
61
+
62
+ 函数 $\textit{dfs}(i)$ 的执行过程如下:
63
+
64
+ - 如果 $i \ge \textit{len}(\textit{nums})$,表示所有房屋都被考虑过了,直接返回 $0$;
65
+ - 否则,考虑偷窃第 $i$ 间房屋,那么 $\textit{dfs}(i) = \textit{nums}[ i] + \textit{dfs}(i+2)$;不偷窃第 $i$ 间房屋,那么 $\textit{dfs}(i) = \textit{dfs}(i+1)$。
66
+ - 返回 $\max(\textit{nums}[ i] + \textit{dfs}(i+2), \textit{dfs}(i+1))$。
67
+
68
+ 为了避免重复计算,我们使用记忆化搜索的方法,将 $\textit{dfs}(i)$ 的结果保存在一个数组或哈希表中,每次计算前先查询是否已经计算过,如果计算过直接返回结果。
69
+
70
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组长度。
71
+
72
+ <!-- tabs:start -->
73
+
74
+ #### Python3
75
+
76
+ ``` python
77
+ class Solution :
78
+ def rob (self , nums : List[int ]) -> int :
79
+ @cache
80
+ def dfs (i : int ) -> int :
81
+ if i >= len (nums):
82
+ return 0
83
+ return max (nums[i] + dfs(i + 2 ), dfs(i + 1 ))
84
+
85
+ return dfs(0 )
86
+ ```
87
+
88
+ #### Java
89
+
90
+ ``` java
91
+ class Solution {
92
+ private Integer [] f;
93
+ private int [] nums;
94
+
95
+ public int rob (int [] nums ) {
96
+ this . nums = nums;
97
+ f = new Integer [nums. length];
98
+ return dfs(0 );
99
+ }
100
+
101
+ private int dfs (int i ) {
102
+ if (i >= nums. length) {
103
+ return 0 ;
104
+ }
105
+ if (f[i] == null ) {
106
+ f[i] = Math . max(nums[i] + dfs(i + 2 ), dfs(i + 1 ));
107
+ }
108
+ return f[i];
109
+ }
110
+ }
111
+ ```
112
+
113
+ #### C++
114
+
115
+ ``` cpp
116
+ class Solution {
117
+ public:
118
+ int rob(vector<int >& nums) {
119
+ int n = nums.size();
120
+ int f[ n] ;
121
+ memset(f, -1, sizeof(f));
122
+ auto dfs = [ &] (auto&& dfs, int i) -> int {
123
+ if (i >= n) {
124
+ return 0;
125
+ }
126
+ if (f[ i] < 0) {
127
+ f[ i] = max(nums[ i] + dfs(dfs, i + 2), dfs(dfs, i + 1));
128
+ }
129
+ return f[ i] ;
130
+ };
131
+ return dfs(dfs, 0);
132
+ }
133
+ };
134
+ ```
135
+
136
+ #### Go
137
+
138
+ ```go
139
+ func rob(nums []int) int {
140
+ n := len(nums)
141
+ f := make([]int, n)
142
+ for i := range f {
143
+ f[i] = -1
144
+ }
145
+ var dfs func(int) int
146
+ dfs = func(i int) int {
147
+ if i >= n {
148
+ return 0
149
+ }
150
+ if f[i] < 0 {
151
+ f[i] = max(nums[i]+dfs(i+2), dfs(i+1))
152
+ }
153
+ return f[i]
154
+ }
155
+ return dfs(0)
156
+ }
157
+ ```
158
+
159
+ #### TypeScript
160
+
161
+ ``` ts
162
+ function rob(nums : number []): number {
163
+ const n = nums .length ;
164
+ const f: number [] = Array (n ).fill (- 1 );
165
+ const dfs = (i : number ): number => {
166
+ if (i >= n ) {
167
+ return 0 ;
168
+ }
169
+ if (f [i ] < 0 ) {
170
+ f [i ] = Math .max (nums [i ] + dfs (i + 2 ), dfs (i + 1 ));
171
+ }
172
+ return f [i ];
173
+ };
174
+ return dfs (0 );
175
+ }
176
+ ```
177
+
178
+ #### Rust
179
+
180
+ ``` rust
181
+ impl Solution {
182
+ pub fn rob (nums : Vec <i32 >) -> i32 {
183
+ fn dfs (i : usize , nums : & Vec <i32 >, f : & mut Vec <i32 >) -> i32 {
184
+ if i >= nums . len () {
185
+ return 0 ;
186
+ }
187
+ if f [i ] < 0 {
188
+ f [i ] = (nums [i ] + dfs (i + 2 , nums , f )). max (dfs (i + 1 , nums , f ));
189
+ }
190
+ f [i ]
191
+ }
192
+
193
+ let n = nums . len ();
194
+ let mut f = vec! [- 1 ; n ];
195
+ dfs (0 , & nums , & mut f )
196
+ }
197
+ }
198
+ ```
199
+
200
+ #### JavaScript
201
+
202
+ ``` js
203
+ function rob (nums ) {
204
+ const n = nums .length ;
205
+ const f = Array (n).fill (- 1 );
206
+ const dfs = i => {
207
+ if (i >= n) {
208
+ return 0 ;
209
+ }
210
+ if (f[i] < 0 ) {
211
+ f[i] = Math .max (nums[i] + dfs (i + 2 ), dfs (i + 1 ));
212
+ }
213
+ return f[i];
214
+ };
215
+ return dfs (0 );
216
+ }
217
+ ```
218
+
219
+ <!-- tabs: end -->
220
+
221
+ <!-- solution: end -->
222
+
223
+ <!-- solution: start -->
224
+
225
+ ### 方法二:动态规划
59
226
60
227
我们定义 $f[ i] $ 表示前 $i$ 间房屋能偷窃到的最高总金额,初始时 $f[ 0] =0$, $f[ 1] =nums[ 0] $。
61
228
@@ -161,12 +328,28 @@ function rob(nums: number[]): number {
161
328
``` rust
162
329
impl Solution {
163
330
pub fn rob (nums : Vec <i32 >) -> i32 {
164
- let mut f = [0 , 0 ];
165
- for x in nums {
166
- f = [f [0 ]. max (f [1 ]), f [0 ] + x ];
331
+ let n = nums . len ();
332
+ let mut f = vec! [0 ; n + 1 ];
333
+ f [1 ] = nums [0 ];
334
+ for i in 2 ..= n {
335
+ f [i ] = f [i - 1 ]. max (f [i - 2 ] + nums [i - 1 ]);
167
336
}
168
- f [0 ]. max (f [1 ])
337
+ f [n ]
338
+ }
339
+ }
340
+ ```
341
+
342
+ #### JavaScript
343
+
344
+ ``` js
345
+ function rob (nums ) {
346
+ const n = nums .length ;
347
+ const f = Array (n + 1 ).fill (0 );
348
+ f[1 ] = nums[0 ];
349
+ for (let i = 2 ; i <= n; ++ i) {
350
+ f[i] = Math .max (f[i - 1 ], f[i - 2 ] + nums[i - 1 ]);
169
351
}
352
+ return f[n];
170
353
}
171
354
```
172
355
@@ -176,7 +359,7 @@ impl Solution {
176
359
177
360
<!-- solution: start -->
178
361
179
- ### 方法二 :动态规划(空间优化)
362
+ ### 方法三 :动态规划(空间优化)
180
363
181
364
我们注意到,当 $i \gt 2$ 时,$f[ i] $ 只和 $f[ i-1] $ 与 $f[ i-2] $ 有关,因此我们可以使用两个变量代替数组,将空间复杂度降到 $O(1)$。
182
365
@@ -250,6 +433,32 @@ function rob(nums: number[]): number {
250
433
}
251
434
```
252
435
436
+ #### Rust
437
+
438
+ ``` rust
439
+ impl Solution {
440
+ pub fn rob (nums : Vec <i32 >) -> i32 {
441
+ let mut f = [0 , 0 ];
442
+ for x in nums {
443
+ f = [f [0 ]. max (f [1 ]), f [0 ] + x ];
444
+ }
445
+ f [0 ]. max (f [1 ])
446
+ }
447
+ }
448
+ ```
449
+
450
+ #### JavaScript
451
+
452
+ ``` js
453
+ function rob (nums ) {
454
+ let [f, g] = [0 , 0 ];
455
+ for (const x of nums) {
456
+ [f, g] = [Math .max (f, g), f + x];
457
+ }
458
+ return Math .max (f, g);
459
+ }
460
+ ```
461
+
253
462
<!-- tabs: end -->
254
463
255
464
<!-- solution: end -->
0 commit comments