【回溯法】leetcode组合、排列
目录
77. 组合
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
这道题是比较简单的回溯法题目,这一题的解答模板就是回溯问题的基本模板
class Solution:
def combine(self, n, k):
output = []
def huisu(lists,start):
for i in range(start,n+1):
new = lists + [i]
if len(new) == k:
output.append(new)
continue
huisu(new,i+1)
huisu([],1)
return output
46. 全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
本题的要点在于每次递归输入的序列,要刨除当前数字:lists[0:index] + lists[index+1:]
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
output = []
length = len(nums)
def huisu(zuhe,lists):
for index,num in enumerate(lists):
new = zuhe + [num]
if len(new) == length:
output.append(new)
else:
huisu(new,lists[0:index] + lists[index+1:])
huisu([],nums)
return output
47. 全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
本题与上一题的区别在于给出的数组里面含有重复的数字,因此首先要排序。之后给出两种方法
方法一:直接加上约束语句if new not in output,也就是不进行枝剪,速度较慢
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums.sort()
output = []
length = len(nums)
def huisu(zuhe,lists):
for index,num in enumerate(lists):
new = zuhe + [num]
if len(new) == length and new not in output:
output.append(new)
else:
huisu(new,lists[0:index] + lists[index+1:])
huisu([],nums)
return output
方法二:进行枝剪
if index > 0 and lists[index] == lists[index-1]:
每当进入新的构成,先考虑该构成的首字符是否和上一个一样,如果一样的话直接跳过
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums.sort()
output = []
length = len(nums)
def huisu(zuhe,lists):
for index,num in enumerate(lists):
if index > 0 and lists[index] == lists[index-1]:
continue
new = zuhe + [num]
if len(new) == length:
output.append(new)
return
huisu(new,lists[0:index] + lists[index+1:])
huisu([],nums)
return output
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
这道题的要点在于对原始的数组进行了排序,并且由于一个元素可以被重复的使用,所以每次递归的数组都要包含当前的元素。
这里面涉及三个枝剪条件:
- 如果当前的数字num>res,说明后面的数字也不会满足要求,直接return
- 如果当前的组合new满足要求,将其添加到output中,则后面的数字也不会满足要求,直接return
- 如果此时数组candidates的第一个元素大于res,也就意味下如果继续递归的话,下一次递归会加上candidates[0],必然会使得res<0,不满足要求。此时直接continue。
例如将示例2中的target改为7,经过3次递归后new = [2,2,2],此时res = 1,而candidates 第一个数字仍为2>res,若继续递归的话,下一个new为[2,2,2,2],res就会变为-1,小于0。为了避免这次不必要的递归,直接在前一次递归,即第3次递归的时候for循环直接跳过2,new变为[2,2,3],就会满足要求
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
output = []
candidates.sort()
def digui(zuhe,candidates, res):
for index,num in enumerate(candidates):
if res - num < 0:
return
new = zuhe + [num]
if res - num == 0:
output.append(new)
return
if res - num < candidates[0]:
continue
digui(new,candidates[index:],res-num)
digui([],candidates, target)
return output
40. 组合总和 II
给定一个可能含有重复数字的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次。
说明:所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
这道题的要点在于对原始的数组进行了排序,例如对于第一个例子,[1,2,5]是一个答案,如果不排序[2,1,5]也会是一个答案。
这里面涉及三个枝剪条件:
- 每当进入新的构成,先考虑该构成的首字符是否和上一个一样,如果一样的话直接跳过,continue
- 如果当前的数字num>res,说明后面的数字也不会满足要求,直接return
- 如果当前的组合new满足要求,将其添加到output中,则后面的数字也不会满足要求,直接return
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
output = []
def digui(candidates,lists,res):
for i,num in enumerate(candidates):
if i > 0 and candidates[i] == candidates[i-1]:
continue
if res - num < 0:
return
new = lists + [num]
if res - num == 0:
output.append(new)
return
digui(candidates[i+1:],new,res - num)
digui(candidates,[],target)
return output
216. 组合总和 III
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
相比于上题,本题更为简单。因为组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字,故不需要在排序了。枝剪条件相同。
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
output = []
candicate = [i for i in range(1,10)]
def huisu(zuhe,candicate,res):
for index, num in enumerate(candicate):
if num > res: #如果当前的数字num>res,说明后面的数字也不会满足要求,直接return
return
new = zuhe + [num]
if res-num == 0 and len(new) == k: #如果num = res,将目前的组合添加进去
output.append(new) #与此同时后面的数字也不会满足要求,返回
return
huisu(new,candicate[index+1:],res-num)
huisu([],candicate,n)
return output
78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。解集不能包含重复的子集。
示例:输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
def subsets(self, nums: List[int]) -> List[List[int]]:
output = []
output.append([])
def digui(zuhe,nums):
if nums == []:
return
for index,num in enumerate(nums):
new = zuhe + [num]
if new not in output:
output.append(new)
digui(new,nums[index+1:])
digui([],nums)
return output
90. 子集 II
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
因为给定的数组nums可能含有重复元素,因此需要排序
def subsets2(self, nums):
output = []
nums.sort()
output.append([])
def digui(zuhe,candidates):
if candidates == []:
return
for index,num in enumerate(candidates):
if index > 0 and candidates[index] == candidates[index-1]:
continue
new = zuhe + [num]
if new not in output:
output.append(new)
digui(new,candidates[index+1:])
digui([],candidates)
return output
本文地址:https://blog.csdn.net/Mr_health/article/details/107657385