回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解。显然,当需要枚举的时候,如果对每种情况都进行循环,那算法的复杂度要O(n^n)。因此,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
回溯算法是一种leetcode刷题过程中出现频率比较高的题目。
针对这种算法,有些大佬总结了一种套路模板如下:
def func(nums):
n = len(nums)
res = []
...
def backtracker(*args):
...
backtracker(*args)
return res
这里针对出现的题目进行一个总结
目录
46. 全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
注意:1.append里面的是nums[:],意思是nums的深拷贝,如果直接写nums返回的结果都是原来的nums;
2.swap(first,i)的意义
def permute(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []
def backtracker(first):
#相当于深拷贝nums,注意这里不可以直接用nums,否则结果没有差异
if first == n: res.append(nums[:])
for i in range(first,n):
#因为是执行深度优先遍历,从较深层的结点返回到较浅层结点的时候,需要做“状态重置”,即“回到过去”、“恢复现场”
nums[first],nums[i] = nums[i],nums[first]
backtracker(first + 1)
nums[first],nums[i] = nums[i],nums[first]
backtracker(0)
return res
47. 全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
思路和全排列1一致,只是在其中加入了一个去重逻辑
def permuteUnique(nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
n = len(nums)
res = []
def backtracker(first):
# 有重复数值和无重复数值的区别
if first == n and nums[:] not in res:
res.append(nums[:])
for i in range(first,n):
nums[first],nums[i] = nums[i],nums[first]
backtracker(first + 1)
nums[first],nums[i] = nums[i],nums[first]
backtracker(0)
return res
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
逻辑:确定数组长度 ——> 生成空数组 ——> 调用递归(三个参数:索引、目标值和保存结果数组)
终止条件:target == 0
def combinationSum(candidates: List[int], target: int) -> List[List[int]]:
n = len(candidates)
res = []
# 注意要先对整个list进行一个排序
candidates.sort()
def backtraker(i,target,tmp_list):
if target == 0:
res.append(tmp_list)
for j in range(i,n):
if target - candidates[j] < 0: break
#题设中的数组是不重复的,所以下面一行其实没意义
if j > i and candidates[j] == candidates[j - 1]: continue
backtraker(j,target - candidates[j] ,tmp_list + [candidates[j]])
backtraker(0,target,[])
return res
40. 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
n = len(candidates)
res = []
# 注意要先对整个list进行一个排序
candidates.sort()
def backtraker(i,target,tmp_list):
if target == 0:
res.append(tmp_list)
for j in range(i,n):
if target - candidates[j] < 0: break
if j > i and candidates[j] == candidates[j - 1]: continue
#注意这一步与组合总和的区别
backtraker(j+1,target - candidates[j] ,tmp_list + [candidates[j]])
backtraker(0,target,[])
return res
来源:CSDN
作者:kunkun_1230
链接:https://blog.csdn.net/weixin_44731100/article/details/103835538