目录
- 一、无重复元素不可复选
- 78.子集
- 77. 组合
- 46. 全排列
- 二、有重复元素不可复选
- 90. 子集 II
- 40.组合总和 II
- 47. 全排列 II
- 三、无重复元素可复选(子集/组合)
- 39. 组合总和
一、无重复元素不可复选
78.子集
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
- 方法一
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
def backtrack(start):
res.append(path[:])
for i in range(start, n):
path.append(nums[i])
# 递归遍历下一层回溯树
# 避免重复使用元素,参数i加1
backtrack(i+1)
path.pop()
res, n = [], len(nums)
# 记录路径
path = []
backtrack(0)
return res
- 方法二
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
def dfs(index, path):
# base case
if index == n:
res.append(path)
return
# 不添加nums[index]
dfs(index+1, path)
# 添加nums[index]
dfs(index+1, path + [nums[index]])
n, res = len(nums), []
dfs(0, [])
return res
77. 组合
给定两个整数 n
和 k
,返回范围 [1, n]
中所有可能的 k
个数的组合。
你可以按 任何顺序 返回答案。
- 方法一
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
def backtrack(start):
# base case
if len(path) == k:
res.append(path[:])
return
for i in range(start, n):
path.append(i+1)
backtrack(i+1)
path.pop()
res = []
path = []
backtrack(0)
return res
- 方法二
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
def dfs(i, path):
if i == n:
if len(path) == k:
res.append(path)
return
dfs(i+1, path)
dfs(i+1, path+[nums[i]])
res = []
nums = list(range(1,n+1))
dfs(0, [])
return res
46. 全排列
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def backtrack(path):
if len(path) == n:
res.append(path[:])
return
for i in nums:
if i in path:
continue
path.append(i)
backtrack(path)
path.pop()
res, n = [], len(nums)
backtrack([])
return res
二、有重复元素不可复选
90. 子集 II
给你一个整数数组 nums
,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
def backtrack(index):
res.append(path[:])
for i in range(index, n):
if i>index and nums[i] == nums[i-1]:
continue
path.append(nums[i])
backtrack(i+1)
path.pop()
nums.sort()
res, n = [], len(nums)
path = []
backtrack(0)
return res
40.组合总和 II
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
**注意:**解集不能包含重复的组合。
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def backtrack(start):
# base case,达到目标和,找到符合条件的组合
if self.pathSum == target:
res.append(path[:])
return
# base case,超过目标和,直接结束
if self.pathSum > target:
return
for i in range(start, n):
# 剪枝,值相同的树枝,只遍历第一条
if i > start and candidates[i] == candidates[i-1]:
continue
path.append(candidates[i])
self.pathSum += candidates[i]
backtrack(i+1)
self.pathSum -= path.pop()
# 先排序,让相同的元素靠在一起
candidates.sort()
res, n = [], len(candidates)
# 记录 path 和 path 中的元素之和
path, self.pathSum = [], 0
backtrack(0)
return res
47. 全排列 II
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
def backtrack(path):
if len(path) == n:
res.append(path[:])
return
for i in range(n):
if used[i] == True:
continue
# 剪枝,同时保证相同元素在排列中的相对位置保持不变
# 注意used[i - 1] == False这个条件
if i > 0 and nums[i] == nums[i-1] and used[i - 1] == False:
continue
path.append(nums[i])
used[i] = True
backtrack(path)
used[i] = False
path.pop()
# 先排序,让相同的元素靠在一起
nums.sort()
res, n = [], len(nums)
# 记录是否使用过该数字
used = [False]*n
backtrack([])
return res
对比之前的标准全排列解法代码,这段解法代码只有两处不同:
1、对 nums
进行了排序。
2、添加了一句额外的剪枝逻辑。
三、无重复元素可复选(子集/组合)
39. 组合总和
给你一个 无重复元素 的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def backtrack(start):
# base case,找到目标和,记录结果
if self.pathSum == target:
res.append(path[:])
return
# base case,超过目标和,停止向下遍历
if self.pathSum > target:
return
for i in range(start, n):
path.append(candidates[i])
self.pathSum += candidates[i]
# 递归遍历下一层回溯树, 同一元素可重复使用,参数填入i
# 可重复选与不可重复选,只有参数ℹ️那里变化
backtrack(i)
self.pathSum -= candidates[i]
path.pop()
res, n = [], len(candidates)
path, self.pathSum = [], 0
backtrack(0)
return res