@@ -66,15 +66,21 @@ tags:
66
66
67
67
<!-- solution:start -->
68
68
69
- ### 方法一:动态规划
69
+ ### 方法一:动态规划(分组背包)
70
70
71
- 对每个栈求前缀和 $s$,$s_i$ 视为一个体积为 $i$ 且价值为 $s_i$ 的物品 。
71
+ 我们定义 $f [ i ] [ j ] $ 表示从前 $i$ 组中取出 $j$ 个硬币的最大面值和,那么答案为 $f [ n ] [ k ] $,其中 $n$ 为栈的数量 。
72
72
73
- 问题转化为求从 $n$ 个物品组中取物品体积为 $k$,且每组最多取一个物品时的最大价值和 。
73
+ 对于第 $i$ 组,我们可以选择取前 $0$, $1$, $2$, $\cdots$, $k$ 个硬币。我们可以通过前缀和数组 $s$ 来快速计算出取前 $h$ 个硬币的面值和 。
74
74
75
- 定义 $dp [ i ] [ j ] $ 表示从前 $i$ 个组中取体积之和为 $j$ 的物品时的最大价值和。
75
+ 状态转移方程为:
76
76
77
- 枚举第 $i$ 组所有物品,设当前物品体积为 $w$,价值为 $v$,则有 $f[ i] [ j ] =max(f[ i] [ j ] ,f[ i-1] [ j-w ] +v)$。
77
+ $$
78
+ f[i][j] = \max(f[i][j], f[i - 1][j - h] + s[h])
79
+ $$
80
+
81
+ 其中 $0 \leq h \leq j$,而 $s[ h] $ 表示第 $i$ 组中取前 $h$ 个硬币的面值和。
82
+
83
+ 时间复杂度 $O(k \times L)$,空间复杂度 $O(n \times k)$。其中 $L$ 为所有硬币的数量,而 $n$ 为栈的数量。
78
84
79
85
<!-- tabs:start -->
80
86
@@ -83,15 +89,16 @@ tags:
83
89
``` python
84
90
class Solution :
85
91
def maxValueOfCoins (self , piles : List[List[int ]], k : int ) -> int :
86
- presum = [list (accumulate(p, initial = 0 )) for p in piles]
87
92
n = len (piles)
88
- dp = [[0 ] * (k + 1 ) for _ in range (n + 1 )]
89
- for i, s in enumerate (presum, 1 ):
93
+ f = [[0 ] * (k + 1 ) for _ in range (n + 1 )]
94
+ for i, nums in enumerate (piles, 1 ):
95
+ s = list (accumulate(nums, initial = 0 ))
90
96
for j in range (k + 1 ):
91
- for idx, v in enumerate (s):
92
- if j >= idx:
93
- dp[i][j] = max (dp[i][j], dp[i - 1 ][j - idx] + v)
94
- return dp[- 1 ][- 1 ]
97
+ for h, w in enumerate (s):
98
+ if j < h:
99
+ break
100
+ f[i][j] = max (f[i][j], f[i - 1 ][j - h] + w)
101
+ return f[n][k]
95
102
```
96
103
97
104
#### Java
@@ -100,26 +107,21 @@ class Solution:
100
107
class Solution {
101
108
public int maxValueOfCoins (List<List<Integer > > piles , int k ) {
102
109
int n = piles. size();
103
- List<int[]> presum = new ArrayList<> ();
104
- for (List<Integer > p : piles) {
105
- int m = p. size();
106
- int [] s = new int [m + 1 ];
107
- for (int i = 0 ; i < m; ++ i) {
108
- s[i + 1 ] = s[i] + p. get(i);
110
+ int [][] f = new int [n + 1 ][k + 1 ];
111
+ for (int i = 1 ; i <= n; i++ ) {
112
+ List<Integer > nums = piles. get(i - 1 );
113
+ int [] s = new int [nums. size() + 1 ];
114
+ s[0 ] = 0 ;
115
+ for (int j = 1 ; j <= nums. size(); j++ ) {
116
+ s[j] = s[j - 1 ] + nums. get(j - 1 );
109
117
}
110
- presum. add(s);
111
- }
112
- int [] dp = new int [k + 1 ];
113
- for (int [] s : presum) {
114
- for (int j = k; j >= 0 ; -- j) {
115
- for (int idx = 0 ; idx < s. length; ++ idx) {
116
- if (j >= idx) {
117
- dp[j] = Math . max(dp[j], dp[j - idx] + s[idx]);
118
- }
118
+ for (int j = 0 ; j <= k; j++ ) {
119
+ for (int h = 0 ; h < s. length && h <= j; h++ ) {
120
+ f[i][j] = Math . max(f[i][j], f[i - 1 ][j - h] + s[h]);
119
121
}
120
122
}
121
123
}
122
- return dp [k];
124
+ return f[n] [k];
123
125
}
124
126
}
125
127
```
@@ -130,22 +132,21 @@ class Solution {
130
132
class Solution {
131
133
public:
132
134
int maxValueOfCoins(vector<vector<int >>& piles, int k) {
133
- vector<vector<int >> presum;
134
- for (auto& p : piles) {
135
- int m = p.size();
136
- vector<int > s(m + 1);
137
- for (int i = 0; i < m; ++i) s[ i + 1] = s[ i] + p[ i] ;
138
- presum.push_back(s);
139
- }
140
- vector<int > dp(k + 1);
141
- for (auto& s : presum) {
142
- for (int j = k; ~ j; --j) {
143
- for (int idx = 0; idx < s.size(); ++idx) {
144
- if (j >= idx) dp[ j] = max(dp[ j] , dp[ j - idx] + s[ idx] );
135
+ int n = piles.size();
136
+ vector<vector<int >> f(n + 1, vector<int >(k + 1));
137
+ for (int i = 1; i <= n; i++) {
138
+ vector<int > nums = piles[ i - 1] ;
139
+ vector<int > s(nums.size() + 1);
140
+ for (int j = 1; j <= nums.size(); j++) {
141
+ s[ j] = s[ j - 1] + nums[ j - 1] ;
142
+ }
143
+ for (int j = 0; j <= k; j++) {
144
+ for (int h = 0; h < s.size() && h <= j; h++) {
145
+ f[ i] [ j ] = max(f[ i] [ j ] , f[ i - 1] [ j - h ] + s[ h] );
145
146
}
146
147
}
147
148
}
148
- return dp [ k] ;
149
+ return f [ n ] [ k ] ;
149
150
}
150
151
};
151
152
```
@@ -154,26 +155,50 @@ public:
154
155
155
156
```go
156
157
func maxValueOfCoins(piles [][]int, k int) int {
157
- var presum [][]int
158
- for _, p := range piles {
159
- m := len(p)
160
- s := make([]int, m+1)
161
- for i, v := range p {
162
- s[i+1] = s[i] + v
163
- }
164
- presum = append(presum, s)
158
+ n := len(piles)
159
+ f := make([][]int, n+1)
160
+ for i := range f {
161
+ f[i] = make([]int, k+1)
165
162
}
166
- dp := make([]int, k+1)
167
- for _, s := range presum {
168
- for j := k; j >= 0; j-- {
169
- for idx, v := range s {
170
- if j >= idx {
171
- dp[j] = max(dp[j], dp[j-idx]+v)
163
+ for i := 1; i <= n; i++ {
164
+ nums := piles[i-1]
165
+ s := make([]int, len(nums)+1)
166
+ for j := 1; j <= len(nums); j++ {
167
+ s[j] = s[j-1] + nums[j-1]
168
+ }
169
+
170
+ for j := 0; j <= k; j++ {
171
+ for h, w := range s {
172
+ if j < h {
173
+ break
172
174
}
175
+ f[i][j] = max(f[i][j], f[i-1][j-h]+w)
173
176
}
174
177
}
175
178
}
176
- return dp[k]
179
+ return f[n][k]
180
+ }
181
+ ```
182
+
183
+ #### TypeScript
184
+
185
+ ``` ts
186
+ function maxValueOfCoins(piles : number [][], k : number ): number {
187
+ const n = piles .length ;
188
+ const f: number [][] = Array .from ({ length: n + 1 }, () => Array (k + 1 ).fill (0 ));
189
+ for (let i = 1 ; i <= n ; i ++ ) {
190
+ const nums = piles [i - 1 ];
191
+ const s = Array (nums .length + 1 ).fill (0 );
192
+ for (let j = 1 ; j <= nums .length ; j ++ ) {
193
+ s [j ] = s [j - 1 ] + nums [j - 1 ];
194
+ }
195
+ for (let j = 0 ; j <= k ; j ++ ) {
196
+ for (let h = 0 ; h < s .length && h <= j ; h ++ ) {
197
+ f [i ][j ] = Math .max (f [i ][j ], f [i - 1 ][j - h ] + s [h ]);
198
+ }
199
+ }
200
+ }
201
+ return f [n ][k ];
177
202
}
178
203
```
179
204
@@ -183,7 +208,11 @@ func maxValueOfCoins(piles [][]int, k int) int {
183
208
184
209
<!-- solution: start -->
185
210
186
- ### 方法二
211
+ ### 方法二:动态规划(空间优化)
212
+
213
+ 我们可以发现,对于第 $i$ 组,我们只需要用到 $f[ i - 1] [ j ] $ 和 $f[ i] [ j - h ] $,因此我们可以将二维数组优化为一维数组。
214
+
215
+ 时间复杂度 $O(k \times L)$,空间复杂度 $O(k)$。
187
216
188
217
<!-- tabs: start -->
189
218
@@ -192,14 +221,100 @@ func maxValueOfCoins(piles [][]int, k int) int {
192
221
``` python
193
222
class Solution :
194
223
def maxValueOfCoins (self , piles : List[List[int ]], k : int ) -> int :
195
- presum = [list (accumulate(p, initial = 0 )) for p in piles]
196
- dp = [ 0 ] * (k + 1 )
197
- for s in presum:
224
+ f = [0 ] * (k + 1 )
225
+ for nums in piles:
226
+ s = list (accumulate(nums, initial = 0 ))
198
227
for j in range (k, - 1 , - 1 ):
199
- for idx, v in enumerate (s):
200
- if j >= idx:
201
- dp[j] = max (dp[j], dp[j - idx] + v)
202
- return dp[- 1 ]
228
+ for h, w in enumerate (s):
229
+ if j < h:
230
+ break
231
+ f[j] = max (f[j], f[j - h] + w)
232
+ return f[k]
233
+ ```
234
+
235
+ #### Java
236
+
237
+ ``` java
238
+ class Solution {
239
+ public int maxValueOfCoins (List<List<Integer > > piles , int k ) {
240
+ int [] f = new int [k + 1 ];
241
+ for (var nums : piles) {
242
+ int [] s = new int [nums. size() + 1 ];
243
+ for (int j = 1 ; j <= nums. size(); ++ j) {
244
+ s[j] = s[j - 1 ] + nums. get(j - 1 );
245
+ }
246
+ for (int j = k; j >= 0 ; -- j) {
247
+ for (int h = 0 ; h < s. length && h <= j; ++ h) {
248
+ f[j] = Math . max(f[j], f[j - h] + s[h]);
249
+ }
250
+ }
251
+ }
252
+ return f[k];
253
+ }
254
+ }
255
+ ```
256
+
257
+ #### C++
258
+
259
+ ``` cpp
260
+ class Solution {
261
+ public:
262
+ int maxValueOfCoins(vector<vector<int >>& piles, int k) {
263
+ vector<int > f(k + 1);
264
+ for (auto& nums : piles) {
265
+ vector<int > s(nums.size() + 1);
266
+ for (int j = 1; j <= nums.size(); ++j) {
267
+ s[ j] = s[ j - 1] + nums[ j - 1] ;
268
+ }
269
+ for (int j = k; j >= 0; --j) {
270
+ for (int h = 0; h < s.size() && h <= j; ++h) {
271
+ f[ j] = max(f[ j] , f[ j - h] + s[ h] );
272
+ }
273
+ }
274
+ }
275
+ return f[ k] ;
276
+ }
277
+ };
278
+ ```
279
+
280
+ #### Go
281
+
282
+ ```go
283
+ func maxValueOfCoins(piles [][]int, k int) int {
284
+ f := make([]int, k+1)
285
+ for _, nums := range piles {
286
+ s := make([]int, len(nums)+1)
287
+ for j := 1; j <= len(nums); j++ {
288
+ s[j] = s[j-1] + nums[j-1]
289
+ }
290
+ for j := k; j >= 0; j-- {
291
+ for h := 0; h < len(s) && h <= j; h++ {
292
+ f[j] = max(f[j], f[j-h]+s[h])
293
+ }
294
+ }
295
+ }
296
+ return f[k]
297
+ }
298
+ ```
299
+
300
+ #### TypeScript
301
+
302
+ ``` ts
303
+ function maxValueOfCoins(piles : number [][], k : number ): number {
304
+ const f: number [] = Array (k + 1 ).fill (0 );
305
+ for (const nums of piles ) {
306
+ const s: number [] = Array (nums .length + 1 ).fill (0 );
307
+ for (let j = 1 ; j <= nums .length ; j ++ ) {
308
+ s [j ] = s [j - 1 ] + nums [j - 1 ];
309
+ }
310
+ for (let j = k ; j >= 0 ; j -- ) {
311
+ for (let h = 0 ; h < s .length && h <= j ; h ++ ) {
312
+ f [j ] = Math .max (f [j ], f [j - h ] + s [h ]);
313
+ }
314
+ }
315
+ }
316
+ return f [k ];
317
+ }
203
318
```
204
319
205
320
<!-- tabs: end -->
0 commit comments