Skip to content

Commit e7ac40e

Browse files
committedApr 17, 2022
feat: add solutions to lc problem: No.0416
No.0416.Partition Equal Subset Sum
1 parent 7db2f04 commit e7ac40e

File tree

9 files changed

+376
-185
lines changed

9 files changed

+376
-185
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
- [两个字符串的最小 ASCII 删除和](/solution/0700-0799/0712.Minimum%20ASCII%20Delete%20Sum%20for%20Two%20Strings/README.md) - 线性 DP、最长公共子序列模型
7979
- [两个字符串的删除操作](/solution/0500-0599/0583.Delete%20Operation%20for%20Two%20Strings/README.md) - 线性 DP、最长公共子序列模型
8080
- [目标和](/solution/0400-0499/0494.Target%20Sum/README.md) - 0-1 背包问题
81+
- [分割等和子集](/solution/0400-0499/0416.Partition%20Equal%20Subset%20Sum/README.md) - 0-1 背包问题
8182
<!-- 背包问题、状态机模型、状压DP、区间DP、树形DP、数位DP 待补充 -->
8283

8384
### 4. 高级数据结构

‎README_EN.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ Complete solutions to [LeetCode](https://leetcode.com/problemset/all/), [LCOF](h
7474
- [Longest Common Subsequence](/solution/1100-1199/1143.Longest%20Common%20Subsequence/README_EN.md) - Linear problem, LCS
7575
- [Minimum ASCII Delete Sum for Two Strings](/solution/0700-0799/0712.Minimum%20ASCII%20Delete%20Sum%20for%20Two%20Strings/README_EN.md) - Linear problem, LCS
7676
- [Delete Operation for Two Strings](/solution/0500-0599/0583.Delete%20Operation%20for%20Two%20Strings/README_EN.md) - Linear problem, LCS
77-
- [Target Sum](/solution/0400-0499/0494.Target%20Sum/README_EN.md) - 0-1 Knapsack
77+
- [Target Sum](/solution/0400-0499/0494.Target%20Sum/README_EN.md) - 0-1 Knapsack problem
78+
- [Partition Equal Subset Sum](/solution/0400-0499/0416.Partition%20Equal%20Subset%20Sum/README_EN.md) - 0-1 Knapsack problem
7879

7980
### 4. Advanced Data Structures
8081

‎solution/0400-0499/0416.Partition Equal Subset Sum/README.md

+147-55
Original file line numberDiff line numberDiff line change
@@ -38,56 +38,53 @@
3838

3939
<!-- 这里可写通用的实现逻辑 -->
4040

41-
题目可以转换为 `0-1` 背包问题,在 m 个数字中选出一些数字(每个数字只能使用一次),这些数字之和恰好等于 `s / 2`(s 表示所有数字之和)。
41+
**方法一:动态规划**
4242

43-
也可以用 DFS + 记忆化搜索。
43+
题目可以转换为 `0-1` 背包问题。
44+
45+
设整数数组总和为 `s`,要使得数组分割成两个元素和相等的子数组,需要满足 s 能够被 2 整除。在此前提下,我们可以将问题抽象为: 从数组中选出若干个数,使得选出的元素之和为 `s/2`。显然这是一个 `0-1` 背包问题。
46+
47+
定义 `dp[i][j]` 表示是否可以从前 i 个数中选出若干个数,使得所选元素之和为 j。
4448

4549
<!-- tabs:start -->
4650

4751
### **Python3**
4852

4953
<!-- 这里可写当前语言的特殊实现逻辑 -->
5054

55+
动态规划——`0-1` 背包朴素做法:
56+
5157
```python
5258
class Solution:
5359
def canPartition(self, nums: List[int]) -> bool:
5460
s = sum(nums)
5561
if s % 2 != 0:
5662
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):
6768
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]]
7071
return dp[-1][-1]
7172
```
7273

73-
空间优化
74+
动态规划——`0-1` 背包空间优化
7475

7576
```python
7677
class Solution:
7778
def canPartition(self, nums: List[int]) -> bool:
7879
s = sum(nums)
7980
if s % 2 != 0:
8081
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)
8484
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]]
9188
return dp[-1]
9289
```
9390

@@ -121,24 +118,49 @@ class Solution:
121118
class Solution {
122119
public boolean canPartition(int[] nums) {
123120
int s = 0;
124-
for (int x : nums) {
125-
s += x;
121+
for (int v : nums) {
122+
s += v;
126123
}
127124
if (s % 2 != 0) {
128125
return false;
129126
}
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;
135153
}
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]];
139161
}
140162
}
141-
return dp[n - 1];
163+
return dp[n];
142164
}
143165
}
144166
```
@@ -150,20 +172,38 @@ class Solution {
150172
public:
151173
bool canPartition(vector<int>& nums) {
152174
int s = 0;
153-
for (int x : nums) s += x;
175+
for (int& v : nums) s += v;
154176
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)
160181
{
161-
for (int j = n - 1; j >= nums[i]; --j)
182+
for (int j = 0; j <= n; ++j)
162183
{
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]];
164186
}
165187
}
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];
167207
}
168208
};
169209
```
@@ -173,27 +213,79 @@ public:
173213
```go
174214
func canPartition(nums []int) bool {
175215
s := 0
176-
for _, x := range nums {
177-
s += x
216+
for _, v := range nums {
217+
s += v
178218
}
179219
if s%2 != 0 {
180220
return false
181221
}
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)
187226
}
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+
}
191234
}
192235
}
193-
return dp[n-1]
236+
return dp[m][n]
194237
}
195238
```
196239

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+
197289
### **...**
198290

199291
```

0 commit comments

Comments
 (0)