回溯算法团灭子集、组合、排列问题
根据元素是否重复和是否可复选,分为以下三种变体:
1、元素无重不可复选
2、元素有重不可复选
3、元素无重可复选
该篇给出第一种情况的代码,另外两种的实现见上方变体链接。
class NoRepeatAndSingle:
"""
元素无重不可复选
"""
def subsets(self, nums: List[int]) -> List[List[int]]:
"""
子集问题
:param nums:[1,2,3]
:return:[[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
"""
self.res = []
self.track = []
self.s_backtrack(nums, 0)
return self.res
def s_backtrack(self, nums, start):
# 前序位置,每个节点的值都是⼀个⼦集
self.res.append(self.track[:])
for i in range(start, len(nums)):
# 做选择
self.track.append(nums[i])
# 通过 start 参数控制树枝的遍历,避免产⽣重复的⼦集
self.s_backtrack(nums, i+1)
# 撤销选择
self.track.pop()
def combination(self, nums: List[int], k: int) -> List[List[int]]:
"""
组合问题
:param nums: [1,2,3]
:param k: 2
:return: [[1, 2], [1, 3], [2, 3]]
"""
self.res = []
self.track = []
self.c_backtrack(nums, 0, k)
return self.res
def c_backtrack(self, nums, start, k):
# base case
if len(self.track) == k:
self.res.append(self.track[:])
return
for i in range(start, len(nums)):
# 做选择
self.track.append(nums[i])
# 通过 start 参数控制树枝的遍历,避免产⽣重复的⼦集
self.c_backtrack(nums, i+1, k)
# 撤销选择
self.track.pop()
def permute(self, nums: List[int]) -> List[List[int]]:
"""
排列问题
:param nums:[1,2,3]
:return:[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
"""
self.res = []
self.track = []
self.used = [False] * len(nums)
self.p_backtrack(nums)
return self.res
def p_backtrack(self, nums):
# base case
if len(self.track) == len(nums):
self.res.append(self.track[:])
return
for i in range(0, len(nums)):
# 已经存在 track 中的元素,不能重复选择
if self.used[i]:
continue
# 做选择
self.used[i] = True
self.track.append(nums[i])
# 通过 start 参数控制树枝的遍历,避免产⽣重复的⼦集
self.p_backtrack(nums)
# 撤销选择
self.used[i] = False
self.track.pop()