From 637e2f4860cf18a6be046ed5eaaffb3c03de7f88 Mon Sep 17 00:00:00 2001 From: Asterisk <44215173+casnz1601@users.noreply.github.com> Date: Sun, 10 Oct 2021 18:08:55 +0800 Subject: [PATCH] =?UTF-8?q?Update=200040.=E7=BB=84=E5=90=88=E6=80=BB?= =?UTF-8?q?=E5=92=8CII.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充python代码和备注 --- problems/0040.组合总和II.md | 99 +++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 13e0b35f..bf2685fb 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -296,24 +296,91 @@ class Solution { ``` ## Python -```python +**回溯+巧妙去重(省去使用used** +```python3 class Solution: + def __init__(self): + self.paths = [] + self.path = [] + def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]: - res = [] - path = [] - def backtrack(candidates,target,sum,startIndex): - if sum == target: res.append(path[:]) - for i in range(startIndex,len(candidates)): #要对同一树层使用过的元素进行跳过 - if sum + candidates[i] > target: return - if i > startIndex and candidates[i] == candidates[i-1]: continue #直接用startIndex来去重,要对同一树层使用过的元素进行跳过 - sum += candidates[i] - path.append(candidates[i]) - backtrack(candidates,target,sum,i+1) #i+1:每个数字在每个组合中只能使用一次 - sum -= candidates[i] #回溯 - path.pop() #回溯 - candidates = sorted(candidates) #首先把给candidates排序,让其相同的元素都挨在一起。 - backtrack(candidates,target,0,0) - return res + ''' + 类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序 + ''' + 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[:]) + 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]: + 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 +``` +**回溯+去重(使用used)** +```python3 +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[:]) + 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: + 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 ``` ## Go: