From 20db57f364270b9c6b9782b1bdaa675c6e1f7152 Mon Sep 17 00:00:00 2001 From: jianghongcheng <35664721+jianghongcheng@users.noreply.github.com> Date: Fri, 26 May 2023 11:10:46 -0500 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 --- problems/0040.组合总和II.md | 143 ++++++++++++++++---------------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index 83708df7..be72d903 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -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 主要在于如何在回溯中去重