Update 0040.组合总和II.md

This commit is contained in:
jianghongcheng
2023-05-26 11:10:46 -05:00
committed by GitHub
parent 2c51420308
commit 20db57f364

View File

@ -354,93 +354,92 @@ class Solution {
``` ```
## Python ## Python
**回溯+巧妙去重(省去使用used** 回溯
```python ```python
class Solution: 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: def backtracking(self, candidates, target, total, startIndex, path, result):
# Base Case if total == target:
if sum_ == target: result.append(path[:])
self.paths.append(self.path[:])
return return
# 单层递归逻辑 for i in range(startIndex, len(candidates)):
for i in range(start_index, len(candidates)): if i > startIndex and candidates[i] == candidates[i - 1]:
# 剪枝同39.组合总和
if sum_ + candidates[i] > target:
return
# 跳过同一树层使用过的元素
if i > start_index and candidates[i] == candidates[i-1]:
continue continue
sum_ += candidates[i] if total + candidates[i] > target:
self.path.append(candidates[i]) break
self.backtracking(candidates, target, sum_, i+1)
self.path.pop() # 回溯为了下一轮for loop total += candidates[i]
sum_ -= candidates[i] # 回溯为了下一轮for loop 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 ```python
class Solution: 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: def backtracking(self, candidates, target, total, startIndex, used, path, result):
# Base Case if total == target:
if sum_ == target: result.append(path[:])
self.paths.append(self.path[:])
return return
# 单层递归逻辑 for i in range(startIndex, len(candidates)):
for i in range(start_index, len(candidates)): # 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字
# 剪枝同39.组合总和 if i > startIndex and candidates[i] == candidates[i - 1] and not used[i - 1]:
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:
continue continue
sum_ += candidates[i] if total + candidates[i] > target:
self.path.append(candidates[i]) break
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
```
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 ## Go
主要在于如何在回溯中去重 主要在于如何在回溯中去重