38
38
39
39
<!-- 这里可写通用的实现逻辑 -->
40
40
41
- 题目可以转换为 ` 0-1 ` 背包问题,在 m 个数字中选出一些数字(每个数字只能使用一次),这些数字之和恰好等于 ` s / 2 ` (s 表示所有数字之和)。
41
+ ** 方法一:动态规划 **
42
42
43
- 也可以用 DFS + 记忆化搜索。
43
+ 题目可以转换为 ` 0-1 ` 背包问题。
44
+
45
+ 设整数数组总和为 ` s ` ,要使得数组分割成两个元素和相等的子数组,需要满足 s 能够被 2 整除。在此前提下,我们可以将问题抽象为: 从数组中选出若干个数,使得选出的元素之和为 ` s/2 ` 。显然这是一个 ` 0-1 ` 背包问题。
46
+
47
+ 定义 ` dp[i][j] ` 表示是否可以从前 i 个数中选出若干个数,使得所选元素之和为 j。
44
48
45
49
<!-- tabs:start -->
46
50
47
51
### ** Python3**
48
52
49
53
<!-- 这里可写当前语言的特殊实现逻辑 -->
50
54
55
+ 动态规划——` 0-1 ` 背包朴素做法:
56
+
51
57
``` python
52
58
class Solution :
53
59
def canPartition (self , nums : List[int ]) -> bool :
54
60
s = sum (nums)
55
61
if s % 2 != 0 :
56
62
return False
57
-
58
- m, n = len (nums), (s >> 1 ) + 1
59
- dp = [[False ] * n for _ in range (m)]
60
- for i in range (m):
61
- dp[i][0 ] = True
62
- if nums[0 ] < n:
63
- dp[0 ][nums[0 ]] = True
64
-
65
- for i in range (1 , m):
66
- for j in range (n):
63
+ m, n = len (nums), s >> 1
64
+ dp = [[False ] * (n + 1 ) for _ in range (m + 1 )]
65
+ dp[0 ][0 ] = True
66
+ for i in range (1 , m + 1 ):
67
+ for j in range (n + 1 ):
67
68
dp[i][j] = dp[i - 1 ][j]
68
- if not dp[i][j] and nums[i] <= j:
69
- dp[i][j] = dp[i - 1 ][j - nums[i]]
69
+ if not dp[i][j] and nums[i - 1 ] <= j:
70
+ dp[i][j] = dp[i - 1 ][j - nums[i - 1 ]]
70
71
return dp[- 1 ][- 1 ]
71
72
```
72
73
73
- 空间优化 :
74
+ 动态规划—— ` 0-1 ` 背包空间优化 :
74
75
75
76
``` python
76
77
class Solution :
77
78
def canPartition (self , nums : List[int ]) -> bool :
78
79
s = sum (nums)
79
80
if s % 2 != 0 :
80
81
return False
81
-
82
- m, n = len (nums), (s >> 1 ) + 1
83
- dp = [False ] * n
82
+ m, n = len (nums), s >> 1
83
+ dp = [False ] * (n + 1 )
84
84
dp[0 ] = True
85
- if nums[0 ] < n:
86
- dp[nums[0 ]] = True
87
-
88
- for i in range (1 , m):
89
- for j in range (n - 1 , nums[i] - 1 , - 1 ):
90
- dp[j] = dp[j] or dp[j - nums[i]]
85
+ for i in range (1 , m + 1 ):
86
+ for j in range (n, nums[i - 1 ] - 1 , - 1 ):
87
+ dp[j] = dp[j] or dp[j - nums[i - 1 ]]
91
88
return dp[- 1 ]
92
89
```
93
90
@@ -121,24 +118,49 @@ class Solution:
121
118
class Solution {
122
119
public boolean canPartition (int [] nums ) {
123
120
int s = 0 ;
124
- for (int x : nums) {
125
- s += x ;
121
+ for (int v : nums) {
122
+ s += v ;
126
123
}
127
124
if (s % 2 != 0 ) {
128
125
return false ;
129
126
}
130
- int m = nums. length, n = (s >> 1 ) + 1 ;
131
- boolean [] dp = new boolean [n];
132
- dp[0 ] = true ;
133
- if (nums[0 ] < n) {
134
- dp[nums[0 ]] = true ;
127
+ int m = nums. length;
128
+ int n = s >> 1 ;
129
+ boolean [][] dp = new boolean [m + 1 ][n + 1 ];
130
+ dp[0 ][0 ] = true ;
131
+ for (int i = 1 ; i <= m; ++ i) {
132
+ for (int j = 0 ; j <= n; ++ j) {
133
+ dp[i][j] = dp[i - 1 ][j];
134
+ if (! dp[i][j] && nums[i - 1 ] <= j) {
135
+ dp[i][j] = dp[i - 1 ][j - nums[i - 1 ]];
136
+ }
137
+ }
138
+ }
139
+ return dp[m][n];
140
+ }
141
+ }
142
+ ```
143
+
144
+ ``` java
145
+ class Solution {
146
+ public boolean canPartition (int [] nums ) {
147
+ int s = 0 ;
148
+ for (int v : nums) {
149
+ s += v;
150
+ }
151
+ if (s % 2 != 0 ) {
152
+ return false ;
135
153
}
136
- for (int i = 1 ; i < m; ++ i) {
137
- for (int j = n - 1 ; j >= nums[i]; -- j) {
138
- dp[j] = dp[j] || dp[j - nums[i]];
154
+ int m = nums. length;
155
+ int n = s >> 1 ;
156
+ boolean [] dp = new boolean [n + 1 ];
157
+ dp[0 ] = true ;
158
+ for (int i = 1 ; i <= m; ++ i) {
159
+ for (int j = n; j >= nums[i - 1 ]; -- j) {
160
+ dp[j] = dp[j] || dp[j - nums[i - 1 ]];
139
161
}
140
162
}
141
- return dp[n - 1 ];
163
+ return dp[n];
142
164
}
143
165
}
144
166
```
@@ -150,20 +172,38 @@ class Solution {
150
172
public:
151
173
bool canPartition(vector<int >& nums) {
152
174
int s = 0;
153
- for (int x : nums) s += x ;
175
+ for (int& v : nums) s += v ;
154
176
if (s % 2 != 0) return false;
155
- int m = nums.size(), n = (s >> 1) + 1;
156
- vector<bool > dp(n);
157
- dp[ 0] = true;
158
- if (nums[ 0] < n) dp[ nums[ 0]] = true;
159
- for (int i = 1; i < m; ++i)
177
+ int m = nums.size(), n = s >> 1;
178
+ vector<vector<bool >> dp(m + 1, vector<bool >(n + 1));
179
+ dp[ 0] [ 0 ] = true;
180
+ for (int i = 1; i <= m; ++i)
160
181
{
161
- for (int j = n - 1 ; j >= nums [ i ] ; -- j)
182
+ for (int j = 0 ; j <= n; ++ j)
162
183
{
163
- dp[ j] = dp[ j] || dp[ j - nums[ i]] ;
184
+ dp[ i] [ j ] = dp[ i - 1] [ j ] ;
185
+ if (!dp[ i] [ j ] && nums[ i - 1] <= j) dp[ i] [ j ] = dp[ i - 1] [ j - nums[ i - 1]] ;
164
186
}
165
187
}
166
- return dp[ n - 1] ;
188
+ return dp[ m] [ n ] ;
189
+ }
190
+ };
191
+ ```
192
+
193
+ ```cpp
194
+ class Solution {
195
+ public:
196
+ bool canPartition(vector<int>& nums) {
197
+ int s = 0;
198
+ for (int& v : nums) s += v;
199
+ if (s % 2 != 0) return false;
200
+ int m = nums.size(), n = s >> 1;
201
+ vector<bool> dp(n + 1);
202
+ dp[0] = true;
203
+ for (int i = 1; i <= m; ++i)
204
+ for (int j = n; j >= nums[i - 1]; --j)
205
+ dp[j] = dp[j] || dp[j - nums[i - 1]];
206
+ return dp[n];
167
207
}
168
208
};
169
209
```
@@ -173,27 +213,79 @@ public:
173
213
``` go
174
214
func canPartition (nums []int ) bool {
175
215
s := 0
176
- for _, x := range nums {
177
- s += x
216
+ for _ , v := range nums {
217
+ s += v
178
218
}
179
219
if s%2 != 0 {
180
220
return false
181
221
}
182
- m, n := len(nums), (s>>1)+1
183
- dp := make([]bool, n)
184
- dp[0] = true
185
- if nums[0] < n {
186
- dp[nums[0]] = true
222
+ m , n := len (nums), s>>1
223
+ dp := make ([][]bool , m+1 )
224
+ for i := range dp {
225
+ dp[i] = make ([]bool , n+1 )
187
226
}
188
- for i := 1; i < m; i++ {
189
- for j := n - 1; j >= nums[i]; j-- {
190
- dp[j] = dp[j] || dp[j-nums[i]]
227
+ dp[0 ][0 ] = true
228
+ for i := 1 ; i <= m; i++ {
229
+ for j := 0 ; j < n; j++ {
230
+ dp[i][j] = dp[i-1 ][j]
231
+ if !dp[i][j] && nums[i-1 ] <= j {
232
+ dp[i][j] = dp[i-1 ][j-nums[i-1 ]]
233
+ }
191
234
}
192
235
}
193
- return dp[n-1 ]
236
+ return dp[m][n ]
194
237
}
195
238
```
196
239
240
+ ``` go
241
+ func canPartition (nums []int ) bool {
242
+ s := 0
243
+ for _ , v := range nums {
244
+ s += v
245
+ }
246
+ if s%2 != 0 {
247
+ return false
248
+ }
249
+ m , n := len (nums), s>>1
250
+ dp := make ([]bool , n+1 )
251
+ dp[0 ] = true
252
+ for i := 1 ; i <= m; i++ {
253
+ for j := n; j >= nums[i-1 ]; j-- {
254
+ dp[j] = dp[j] || dp[j-nums[i-1 ]]
255
+ }
256
+ }
257
+ return dp[n]
258
+ }
259
+ ```
260
+
261
+ ### ** JavaScript**
262
+
263
+ ``` js
264
+ /**
265
+ * @param {number[]} nums
266
+ * @return {boolean}
267
+ */
268
+ var canPartition = function (nums ) {
269
+ let s = 0 ;
270
+ for (let v of nums) {
271
+ s += v;
272
+ }
273
+ if (s % 2 != 0 ) {
274
+ return false ;
275
+ }
276
+ const m = nums .length ;
277
+ const n = s >> 1 ;
278
+ const dp = new Array (n + 1 ).fill (false );
279
+ dp[0 ] = true ;
280
+ for (let i = 1 ; i <= m; ++ i) {
281
+ for (let j = n; j >= nums[i - 1 ]; -- j) {
282
+ dp[j] = dp[j] || dp[j - nums[i - 1 ]];
283
+ }
284
+ }
285
+ return dp[n];
286
+ };
287
+ ```
288
+
197
289
### ** ...**
198
290
199
291
```
0 commit comments