Skip to content

Commit 637e2f4

Browse files
authored
Update 0040.组合总和II.md
补充python代码和备注
1 parent b5dcc55 commit 637e2f4

File tree

1 file changed

+83
-16
lines changed

1 file changed

+83
-16
lines changed

problems/0040.组合总和II.md

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -296,24 +296,91 @@ class Solution {
296296
```
297297

298298
## Python
299-
```python
299+
**回溯+巧妙去重(省去使用used**
300+
```python3
300301
class Solution:
302+
def __init__(self):
303+
self.paths = []
304+
self.path = []
305+
306+
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
307+
'''
308+
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
309+
'''
310+
self.paths.clear()
311+
self.path.clear()
312+
# 必须提前进行数组排序,避免重复
313+
candidates.sort()
314+
self.backtracking(candidates, target, 0, 0)
315+
return self.paths
316+
317+
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
318+
# Base Case
319+
if sum_ == target:
320+
self.paths.append(self.path[:])
321+
return
322+
323+
# 单层递归逻辑
324+
for i in range(start_index, len(candidates)):
325+
# 剪枝,同39.组合总和
326+
if sum_ + candidates[i] > target:
327+
return
328+
329+
# 跳过同一树层使用过的元素
330+
if i > start_index and candidates[i] == candidates[i-1]:
331+
continue
332+
333+
sum_ += candidates[i]
334+
self.path.append(candidates[i])
335+
self.backtracking(candidates, target, sum_, i+1)
336+
self.path.pop() # 回溯,为了下一轮for loop
337+
sum_ -= candidates[i] # 回溯,为了下一轮for loop
338+
```
339+
**回溯+去重(使用used)**
340+
```python3
341+
class Solution:
342+
def __init__(self):
343+
self.paths = []
344+
self.path = []
345+
self.used = []
346+
301347
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
302-
res = []
303-
path = []
304-
def backtrack(candidates,target,sum,startIndex):
305-
if sum == target: res.append(path[:])
306-
for i in range(startIndex,len(candidates)): #要对同一树层使用过的元素进行跳过
307-
if sum + candidates[i] > target: return
308-
if i > startIndex and candidates[i] == candidates[i-1]: continue #直接用startIndex来去重,要对同一树层使用过的元素进行跳过
309-
sum += candidates[i]
310-
path.append(candidates[i])
311-
backtrack(candidates,target,sum,i+1) #i+1:每个数字在每个组合中只能使用一次
312-
sum -= candidates[i] #回溯
313-
path.pop() #回溯
314-
candidates = sorted(candidates) #首先把给candidates排序,让其相同的元素都挨在一起。
315-
backtrack(candidates,target,0,0)
316-
return res
348+
'''
349+
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
350+
本题需要使用used,用来标记区别同一树层的元素使用重复情况:注意区分递归纵向遍历遇到的重复元素,和for循环遇到的重复元素,这两者的区别
351+
'''
352+
self.paths.clear()
353+
self.path.clear()
354+
self.usage_list = [False] * len(candidates)
355+
# 必须提前进行数组排序,避免重复
356+
candidates.sort()
357+
self.backtracking(candidates, target, 0, 0)
358+
return self.paths
359+
360+
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
361+
# Base Case
362+
if sum_ == target:
363+
self.paths.append(self.path[:])
364+
return
365+
366+
# 单层递归逻辑
367+
for i in range(start_index, len(candidates)):
368+
# 剪枝,同39.组合总和
369+
if sum_ + candidates[i] > target:
370+
return
371+
372+
# 检查同一树层是否出现曾经使用过的相同元素
373+
# 若数组中前后元素值相同,但前者却未被使用(used == False),说明是for loop中的同一树层的相同元素情况
374+
if i > 0 and candidates[i] == candidates[i-1] and self.usage_list[i-1] == False:
375+
continue
376+
377+
sum_ += candidates[i]
378+
self.path.append(candidates[i])
379+
self.usage_list[i] = True
380+
self.backtracking(candidates, target, sum_, i+1)
381+
self.usage_list[i] = False # 回溯,为了下一轮for loop
382+
self.path.pop() # 回溯,为了下一轮for loop
383+
sum_ -= candidates[i] # 回溯,为了下一轮for loop
317384
```
318385

319386
## Go:

0 commit comments

Comments
 (0)