-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathcombination-sum.py
209 lines (171 loc) · 6.16 KB
/
combination-sum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""
39. Combination Sum
Medium
Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order.
The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.
It is guaranteed that the number of unique combinations that sum up to target is less than 150 combinations for the given input.
Example 1:
Input: candidates = [2,3,6,7], target = 7
Output: [[2,2,3],[7]]
Explanation:
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
7 is a candidate, and 7 = 7.
These are the only two combinations.
Example 2:
Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]
Example 3:
Input: candidates = [2], target = 1
Output: []
Example 4:
Input: candidates = [1], target = 1
Output: [[1]]
Example 5:
Input: candidates = [1], target = 2
Output: [[1,1]]
Constraints:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
All elements of candidates are distinct.
1 <= target <= 500
"""
# V0
# IDEA : DFS + BACKTRACK
class Solution(object):
def combinationSum(self, candidates, target):
def dfs(tmp):
if sum(tmp) == target:
tmp.sort()
if tmp not in res:
res.append(tmp)
return
if sum(tmp) > target:
return
for c in candidates:
### NOTE : we can add tmp with [c] in func arg directly (as below)
dfs(tmp + [c])
res = []
tmp = []
dfs(tmp)
return res
# V0'
# IDEA : DFS + BACKTRACK
class Solution(object):
def combinationSum(self, candidates, target):
res = []
candidates.sort()
self.dfs(candidates, target, 0, res, [])
return res
def dfs(self, nums, target, index, res, path):
if target < 0:
return
elif target == 0:
res.append(path)
return
for i in range(index, len(nums)):
if nums[index] > target:
return
self.dfs(nums, target - nums[i], i, res, path + [nums[i]])
# V1
# https://blog.csdn.net/fuxuemingzhu/article/details/79322462
# IDEA : DFS
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
candidates.sort() # sort the candidates first, for the following "if nums[index] > target: return" logic n "
self.dfs(candidates, target, 0, res, [])
return res
def dfs(self, nums, target, index, res, path):
if target < 0:
return
elif target == 0:
res.append(path)
return
for i in range(index, len(nums)):
if nums[index] > target: # if the current value in candidates already > target, that means there is no such collection can make its sum as same as target
return
self.dfs(nums, target - nums[i], i, res, path + [nums[i]])
# V1
# https://github.com/neetcode-gh/leetcode/blob/main/python/0039-combination-sum.py
# https://www.youtube.com/watch?v=GBKI9VSKdGg
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
def dfs(i, cur, total):
if total == target:
res.append(cur.copy())
return
if i >= len(candidates) or total > target:
return
cur.append(candidates[i])
dfs(i, cur, total + candidates[i])
cur.pop()
dfs(i + 1, cur, total)
dfs(0, [], 0)
return res
### Test case : dev
# V1'
# https://leetcode.com/problems/combination-sum/discuss/16554/Share-My-Python-Solution-beating-98.17
# IDEA : BACKTRACKING
class Solution(object):
def combinationSum(self, candidates, target):
result = []
candidates = sorted(candidates)
def dfs(remain, stack):
if remain == 0:
result.append(stack)
return
for item in candidates:
if item > remain: break
if stack and item < stack[-1]: continue
else:
dfs(remain - item, stack + [item])
dfs(target, [])
return result
# V1''
# https://www.jiuzhang.com/solution/combination-sum/#tag-highlight-lang-python
class Solution:
# @param candidates, a list of integers
# @param target, integer
# @return a list of lists of integers
def combinationSum(self, candidates, target):
candidates = sorted(list(set(candidates)))
results = []
self.dfs(candidates, target, 0, [], results)
return results
def dfs(self, candidates, target, start, combination, results):
if target < 0:
return
if target == 0:
# deepcooy
return results.append(list(combination))
for i in range(start, len(candidates)):
# [2] => [2,2]
combination.append(candidates[i])
self.dfs(candidates, target - candidates[i], i, combination, results)
# [2,2] => [2]
combination.pop() # backtracking
# V2
# Time: O(k * n^k)
# Space: O(k)
class Solution(object):
# @param candidates, a list of integers
# @param target, integer
# @return a list of lists of integers
def combinationSum(self, candidates, target):
result = []
self.combinationSumRecu(sorted(candidates), result, 0, [], target)
return result
def combinationSumRecu(self, candidates, result, start, intermediate, target):
if target == 0:
result.append(list(intermediate))
while start < len(candidates) and candidates[start] <= target:
intermediate.append(candidates[start])
self.combinationSumRecu(candidates, result, start, intermediate, target - candidates[start])
intermediate.pop()
start += 1