Skip to content

Commit e369073

Browse files
Create 0416-partition-equal-subset-sum.go
I also added a solution which works in reverse, by remembering the numbers that can not be solved for. The algorithm runs in 5ms as opposed to 313ms for the implementation in the video. I believe that the reverse algorithm has a faster runtime because we never need to duplicate the set of unsolvable numbers.
1 parent 568d467 commit e369073

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

Diff for: go/0416-partition-equal-subset-sum.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
func canPartitionTabulation(nums []int) bool {
2+
sum := sum(nums)
3+
if sum % 2 != 0 {
4+
return false
5+
}
6+
7+
dp := make(map[int]bool)
8+
dp[0] = true
9+
target := sum / 2
10+
11+
for i := len(nums) - 1; i >= 0; i-- {
12+
nextDP := make(map[int]bool)
13+
for t, _ := range dp {
14+
if (t + nums[i]) == target {
15+
return true
16+
}
17+
nextDP[t + nums[i]] = true
18+
nextDP[t] = true
19+
}
20+
dp = nextDP
21+
}
22+
return false
23+
}
24+
25+
func sum(nums []int) int {
26+
res := 0
27+
for _, num := range nums {
28+
res += num
29+
}
30+
return res
31+
}
32+
33+
34+
35+
const NUM = 0
36+
const FREQ = 1
37+
type byNum [][]int
38+
func (s byNum) Len() int {return len(s)}
39+
func (s byNum) Swap(i, j int) {s[i], s[j] = s[j], s[i]}
40+
func (s byNum) Less(i, j int) bool {return s[i][NUM] > s[j][NUM]}
41+
42+
func canPartitionMemoization(nums[] int) bool {
43+
count := make(map[int]int)
44+
sum := 0
45+
for _, n := range nums {
46+
count[n] += 1
47+
sum += n
48+
}
49+
50+
if sum % 2 != 0 {
51+
return false
52+
}
53+
54+
numsF := make([][]int, len(count))
55+
idx := 0
56+
for num, freq := range count {
57+
numsF[idx] = []int{num, freq}
58+
idx++
59+
}
60+
sort.Sort(byNum(numsF))
61+
visited := make([]bool, sum/2 + 1)
62+
visited[0] = true
63+
return solveCanPartition(visited, numsF, sum/2)
64+
}
65+
66+
func solveCanPartition(visited []bool, nums [][]int, target int) bool {
67+
if visited[target] {
68+
return target == 0
69+
}
70+
visited[target] = true
71+
72+
for index := predecessor(nums, target); index < len(nums); index++ {
73+
nums[index][FREQ]--
74+
if nums[index][FREQ] >= 0 && solveCanPartition(visited, nums, target - nums[index][NUM]) {
75+
return true
76+
}
77+
nums[index][FREQ]++
78+
}
79+
80+
return false
81+
}
82+
83+
func predecessor(nums [][]int, target int) int {
84+
l := 0
85+
h := len(nums) - 1
86+
for h - l > 1 {
87+
m := (h + l)/2
88+
if nums[m][NUM] > target {
89+
l = m + 1
90+
} else {
91+
h = m
92+
}
93+
}
94+
95+
if nums[l][0] <= target {
96+
return l
97+
} else if nums[h][0] <= target {
98+
return h
99+
} else {
100+
return math.MaxInt32
101+
}
102+
}

0 commit comments

Comments
 (0)