😡😡😡
声明:
算法基于https://labuladong.github.io/
同步git地址:https://github.com/muxintong/break-algorithm/
python语言实现
39.combination-sum
40.combination-sum-ii
😡😡😡
39.combination-sum
39.combination-sum_1
from typing import List
class Solution:
'''
【子集/组合(元素无重可复选)】
1.标准的子集/组合问题是如何保证【不重复使用】元素的?
backtrack 递归时输入的参数 start:
这个 i 从 start 开始,那么下一层回溯树就是从 【i+1】 开始,从而保证 nums[start] 这个元素不会被重复使用。
2.那么反过来,如果我想让每个元素被【重复使用】,我只要把 i + 1 改成 【i】 即可:
这相当于给之前的回溯树添加了一条树枝,在遍历这棵树的过程中,一个元素可以被无限次使用:
当然,这样这棵回溯树会永远生长下去,所以我们的递归函数需要设置合适的base case以结束算法,即路径和大于 target 时就没必要再遍历下去了。
'''
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
track = []
track_sum = 0
start = 0
def backtrack(start: int, track_sum: int):
# base case:递归出口1
if track_sum == target:
res.append(track.copy())
return
# base case:递归出口2
if track_sum > target:
return
for i in range(start, len(candidates), 1):
if candidates[i] + track_sum > target:
continue
elif candidates[i] + track_sum <= target:
track_sum += candidates[i]
track.append(candidates[i])
# keypoint:若元素可重复使用,则递归调用仍从i开始。
backtrack(i, track_sum)
track_sum -= candidates[i]
track.remove(candidates[i])
backtrack(start, track_sum)
return res
def main():
# Input: candidates = [2,3,6,7], target = 7
# Output: [[2,2,3],[7]]
# Explanation:
# 2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
# 7 is a candidate, and 7 = 7.
# These are the only two combinations.
solution1 = Solution()
print(solution1.combinationSum(candidates=[2, 3, 6, 7], target=7))
print('---')
# Input: candidates = [2,3,5], target = 8
# Output: [[2,2,2,2],[2,3,3],[3,5]]
solution2 = Solution()
print(solution2.combinationSum(candidates = [2,3,5], target = 8))
print('---')
# Input: candidates = [2], target = 1
# Output: []
solution3 = Solution()
print(solution3.combinationSum(candidates = [2], target = 1))
if __name__ == '__main__':
main()
39.combination-sum_2
from typing import List
class Solution:
'''
【子集/组合(元素无重可复选)】
1.标准的子集/组合问题是如何保证【不重复使用】元素的?
backtrack 递归时输入的参数 start:
这个 i 从 start 开始,那么下一层回溯树就是从 【i+1】 开始,从而保证 nums[start] 这个元素不会被重复使用。
2.那么反过来,如果我想让每个元素被【重复使用】,我只要把 i + 1 改成 【i】 即可:
这相当于给之前的回溯树添加了一条树枝,在遍历这棵树的过程中,一个元素可以被无限次使用:
当然,这样这棵回溯树会永远生长下去,所以我们的递归函数需要设置合适的base case以结束算法,即路径和大于 target 时就没必要再遍历下去了。
'''
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
track = []
track_sum = 0
start = 0
def backtrack(start: int, track_sum: int):
# base case:递归出口1
if track_sum == target:
res.append(track.copy())
return
# base case:递归出口2
if track_sum > target:
return
for i in range(start, len(candidates), 1):
if candidates[i] + track_sum > target:
continue
elif candidates[i] + track_sum <= target:
track_sum += candidates[i]
track.append(candidates[i])
# keypoint:若元素可重复使用,则递归调用仍从i开始。
backtrack(i, track_sum)
track_sum -= candidates[i]
track.remove(candidates[i])
backtrack(start, track_sum)
return res
def main():
# Input: candidates = [2,3,6,7], target = 7
# Output: [[2,2,3],[7]]
# Explanation:
# 2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
# 7 is a candidate, and 7 = 7.
# These are the only two combinations.
solution1 = Solution()
print(solution1.combinationSum(candidates=[2, 3, 6, 7], target=7))
print('---')
# Input: candidates = [2,3,5], target = 8
# Output: [[2,2,2,2],[2,3,3],[3,5]]
solution2 = Solution()
print(solution2.combinationSum(candidates = [2,3,5], target = 8))
print('---')
# Input: candidates = [2], target = 1
# Output: []
solution3 = Solution()
print(solution3.combinationSum(candidates = [2], target = 1))
if __name__ == '__main__':
main()
😡😡😡
40.combination-sum-ii
40.combination-sum-ii(先排序+相同元素仅处理一次:保证去重)
from typing import List
class Solution:
'''
(先排序+相同元素仅处理一次:保证去重)
先对输入列表排序,在回溯算法的递归调用中通过对相同元素只处理一次的方法进行去重
'''
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
# 最终结果集res:存储各个track
res = []
# 路径列表track:存储符合题意的选择i对应的值candidates[i]
track = []
track_sum = 0
# 组合|子集类问题:
# 使用起始位start保证元素顺序=>从而保证结果子集与元素顺序无关,为组合型问题,而非排列型问题。
start = 0
candidates.sort()
def backtrack(start: int, track_sum: int):
# 1 递归出口
if track_sum == target:
res.append(track.copy())
return
for i in range(start, len(candidates), 1):
if i>start and candidates[i]==candidates[i-1]:
continue
# 2.1 选择判断:是否符合题意
# 若不符合:
if candidates[i] + track_sum > target:
continue
# 若符合:
elif candidates[i] + track_sum <= target:
track_sum += candidates[i]
track.append(candidates[i])
# 2.2 递归
backtrack(i + 1, track_sum)
# 2.3 递归后撤销符合题意的选择
track.remove(candidates[i])
track_sum -= candidates[i]
backtrack(start, track_sum)
return res
def main():
# Input: candidates = [10,1,2,7,6,1,5], target = 8
# Output:
# [
# [1,1,6],
# [1,2,5],
# [1,7],
# [2,6]
# ]
solution1 = Solution()
print(solution1.combinationSum2(candidates=[10, 1, 2, 7, 6, 1, 5], target=8))
print('---')
# Input: candidates = [2,5,2,1,2], target = 5
# Output:
# [
# [1,2,2],
# [5]
# ]
solution2 = Solution()
print(solution2.combinationSum2(candidates=[2, 5, 2, 1, 2], target=5))
if __name__ == '__main__':
main()
40.combination-sum-ii(对结果集去重)
from typing import List
class Solution:
'''
(对结果集去重)
'''
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
track = []
track_sum = 0
start = 0
def backtrack(start: int, track_sum: int):
# 1.递归出口
if track_sum == target:
res.append(track.copy())
return
# 2.组合|子集类问题使用起始位start保证元素顺序
for i in range(start, len(candidates), 1):
# 2.1 判断选择i是否符合题意
# 若不符合
if track_sum + candidates[i] > target:
continue
# 若符合:做选择
else:
track.append(candidates[i])
track_sum += candidates[i]
# 2.2 递归
backtrack(i + 1, track_sum)
# 2.3 递归后撤销选择
track.remove(candidates[i])
track_sum -= candidates[i]
backtrack(start, track_sum)
# 针对res去重
res = [sorted(i) for i in res]
res_tup_nodup = list(set([tuple(i) for i in res]))
res_list_nodup = [list(i) for i in res_tup_nodup]
return res_list_nodup
def main():
# Input: candidates = [10,1,2,7,6,1,5], target = 8
# Output:
# [
# [1,1,6],
# [1,2,5],
# [1,7],
# [2,6]
# ]
solution1 = Solution()
print(solution1.combinationSum2(candidates=[10, 1, 2, 7, 6, 1, 5], target=8))
print('---')
# Input: candidates = [2,5,2,1,2], target = 5
# Output:
# [
# [1,2,2],
# [5]
# ]
solution2 = Solution()
print(solution2.combinationSum2(candidates=[2, 5, 2, 1, 2], target=5))
if __name__ == '__main__':
main()
😡😡😡
😡😡😡
😡😡😡