基础版回溯函数参数只有(target, show),target是目标大小,show是递归传递的变量。
- 一个数字只能用一次,那下次递归时就把这次用去掉 nums[:i]+nums[i+1:]
- [1,2,3]和[3,2,1]算重复,那么加入索引,每次都往后找
- 要求组合长度为k,那就放个变量 count 计数
- 如果候选列表有重复的话,先排序,再前后两个进行判断
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
nums = [1,2,3,4,5,6,7,8,9,1,2]
nums.sort()
res = []
def backtrack(target, show, nums, idx, count):
if target == 0 and count == k:
res.append(show[:])
return
if target < 0 or count > k:
return
for i in range(idx, len(nums)):
if i>idx and nums[i] == nums[i-1]:
continue
backtrack(target-nums[i], show+[nums[i]], nums[:i]+nums[i+1:], i, count+1)
return res
return backtrack(n, [], nums, 0, 0)
上面这套模板可以做排列,组合和子集问题。
如果是切割问题的话,用下面的模板:
每次改变的是切割的起始点 idx,原字符串 s 并没有改变。
class Solution:
def partition(self, s: str) -> List[List[str]]:
def isvalid(s):
i = 0
j = len(s)-1
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True
res = []
path = []
def backtrack(s, idx):
if idx==len(s):
res.append(path[:])
return
for i in range(idx, len(s)):
if isvalid(s[idx:i+1]):
path.append(s[idx:i+1])
backtrack(s,i+1)
path.pop()
return res
return backtrack(s,0)
下面的递增子序列类似于子集问题,需要注意
- 单向寻找,回溯时取nums[i+1:]
- 不能排序,所以哈希去重
- 判断相邻元素的大小时的边界问题
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(nums, path):
ht = {}
if len(path)>1:
res.append(path[:])
for i in range(len(nums)):
if len(path)>0:
if nums[i]<path[-1]:
continue
if nums[i] in ht:
continue
ht[nums[i]] = i
backtrack(nums[i+1:], path+[nums[i]])
return res
return backtrack(nums, [])
猜你喜欢:👇🏻
⭐【Leetcode】背包问题模板
⭐【Leetcode】几种简单的排序算法
⭐【Leetcode】二分法左侧边界右侧边界模板