mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-11 04:54:51 +08:00
Update 0040.组合总和II.md
This commit is contained in:
@ -354,93 +354,92 @@ class Solution {
|
||||
```
|
||||
|
||||
## Python
|
||||
**回溯+巧妙去重(省去使用used**
|
||||
回溯
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
|
||||
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||
'''
|
||||
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
|
||||
'''
|
||||
self.paths.clear()
|
||||
self.path.clear()
|
||||
# 必须提前进行数组排序,避免重复
|
||||
candidates.sort()
|
||||
self.backtracking(candidates, target, 0, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||
# Base Case
|
||||
if sum_ == target:
|
||||
self.paths.append(self.path[:])
|
||||
def backtracking(self, candidates, target, total, startIndex, path, result):
|
||||
if total == target:
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(candidates)):
|
||||
# 剪枝,同39.组合总和
|
||||
if sum_ + candidates[i] > target:
|
||||
return
|
||||
|
||||
# 跳过同一树层使用过的元素
|
||||
if i > start_index and candidates[i] == candidates[i-1]:
|
||||
for i in range(startIndex, len(candidates)):
|
||||
if i > startIndex and candidates[i] == candidates[i - 1]:
|
||||
continue
|
||||
|
||||
sum_ += candidates[i]
|
||||
self.path.append(candidates[i])
|
||||
self.backtracking(candidates, target, sum_, i+1)
|
||||
self.path.pop() # 回溯,为了下一轮for loop
|
||||
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
||||
if total + candidates[i] > target:
|
||||
break
|
||||
|
||||
total += candidates[i]
|
||||
path.append(candidates[i])
|
||||
self.backtracking(candidates, target, total, i + 1, path, result)
|
||||
total -= candidates[i]
|
||||
path.pop()
|
||||
|
||||
def combinationSum2(self, candidates, target):
|
||||
result = []
|
||||
candidates.sort()
|
||||
self.backtracking(candidates, target, 0, 0, [], result)
|
||||
return result
|
||||
|
||||
```
|
||||
**回溯+去重(使用used)**
|
||||
回溯+去重(使用used)
|
||||
```python
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.paths = []
|
||||
self.path = []
|
||||
self.used = []
|
||||
|
||||
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||
'''
|
||||
类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
|
||||
本题需要使用used,用来标记区别同一树层的元素使用重复情况:注意区分递归纵向遍历遇到的重复元素,和for循环遇到的重复元素,这两者的区别
|
||||
'''
|
||||
self.paths.clear()
|
||||
self.path.clear()
|
||||
self.usage_list = [False] * len(candidates)
|
||||
# 必须提前进行数组排序,避免重复
|
||||
candidates.sort()
|
||||
self.backtracking(candidates, target, 0, 0)
|
||||
return self.paths
|
||||
|
||||
def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
|
||||
# Base Case
|
||||
if sum_ == target:
|
||||
self.paths.append(self.path[:])
|
||||
def backtracking(self, candidates, target, total, startIndex, used, path, result):
|
||||
if total == target:
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
# 单层递归逻辑
|
||||
for i in range(start_index, len(candidates)):
|
||||
# 剪枝,同39.组合总和
|
||||
if sum_ + candidates[i] > target:
|
||||
return
|
||||
|
||||
# 检查同一树层是否出现曾经使用过的相同元素
|
||||
# 若数组中前后元素值相同,但前者却未被使用(used == False),说明是for loop中的同一树层的相同元素情况
|
||||
if i > 0 and candidates[i] == candidates[i-1] and self.usage_list[i-1] == False:
|
||||
for i in range(startIndex, len(candidates)):
|
||||
# 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字
|
||||
if i > startIndex and candidates[i] == candidates[i - 1] and not used[i - 1]:
|
||||
continue
|
||||
|
||||
sum_ += candidates[i]
|
||||
self.path.append(candidates[i])
|
||||
self.usage_list[i] = True
|
||||
self.backtracking(candidates, target, sum_, i+1)
|
||||
self.usage_list[i] = False # 回溯,为了下一轮for loop
|
||||
self.path.pop() # 回溯,为了下一轮for loop
|
||||
sum_ -= candidates[i] # 回溯,为了下一轮for loop
|
||||
```
|
||||
if total + candidates[i] > target:
|
||||
break
|
||||
|
||||
total += candidates[i]
|
||||
path.append(candidates[i])
|
||||
used[i] = True
|
||||
self.backtracking(candidates, target, total, i + 1, used, path, result)
|
||||
used[i] = False
|
||||
total -= candidates[i]
|
||||
path.pop()
|
||||
|
||||
def combinationSum2(self, candidates, target):
|
||||
used = [False] * len(candidates)
|
||||
result = []
|
||||
candidates.sort()
|
||||
self.backtracking(candidates, target, 0, 0, used, [], result)
|
||||
return result
|
||||
|
||||
```
|
||||
回溯优化
|
||||
```python
|
||||
class Solution:
|
||||
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
|
||||
candidates.sort()
|
||||
results = []
|
||||
self.combinationSumHelper(candidates, target, 0, [], results)
|
||||
return results
|
||||
|
||||
def combinationSumHelper(self, candidates, target, index, path, results):
|
||||
if target == 0:
|
||||
results.append(path[:])
|
||||
return
|
||||
for i in range(index, len(candidates)):
|
||||
if i > index and candidates[i] == candidates[i - 1]:
|
||||
continue
|
||||
if candidates[i] > target:
|
||||
break
|
||||
path.append(candidates[i])
|
||||
self.combinationSumHelper(candidates, target - candidates[i], i + 1, path, results)
|
||||
path.pop()
|
||||
```
|
||||
## Go
|
||||
主要在于如何在回溯中去重
|
||||
|
||||
|
Reference in New Issue
Block a user