回溯法(递归的一种)
回溯算法的递归使用以及剪枝策略。
回溯法:一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
正规写法:
t = [] def dps(cur,n): if cur == n: return t.append(cur) dps(cur+1,n) t.pop() dps(cur+1,n) dps(0,n)
|
简便写法:
def dps(i,tmp): for j in range(i,n): dps(j+1, tmp + j) dps(0,[])
|
如果涉及剪枝或避免重复元素:
- 先进行排序,保证重复的元素放在一起
- 然后回溯选取下一个节点的时候判断一下是否和前面的相同,相同的则不用再继续遍历,相当于剪枝;不同则要继续遍历。
简便写法:
nums.sort() def dps(i,tmp): for j in range(i,n): if j > i and nums[j] == nums[j-1]: continue dps(j+1, tmp+ [nums[j]]) dps(0,[])
|
值传递、引用传递、浅拷贝、深拷贝
值传递和引用传递
不可变类型在传递参数时都是传值形式,如int,str,tuple类型。
可变类型在传递参数时都是引用传递,如list,set,dict类型。指向的都是同一块内存地址
值传递:当元素被赋予新值或者修改值的时候,是指向了一个新的对象,和原对象无关。当原值没有对象再指向它,就会被python的GC回收。
引用传递:指向的都是同一块内存地址,一旦改变值,所有指向这个内存地址的都会改变
拷贝的内置函数
copy()浅拷贝:不拷贝对象的内容,只拷贝子对象的引用,原数据改变,则子对象会改变
deepcopy()深拷贝:对子对象的内存也会拷贝一份,对子对象的修改不会影响源对象,原始数据的改变不会影响深拷贝
a = b: 引用传递
a.copy():浅拷贝
copy.copy(a):浅拷贝
copy.deepcopy(a):深拷贝
区别nums和nums[:]
nums[:] = nums[0:len(nums)] 可以使用[:]来拷贝全部元素
nums[:]在计算机中是新分配了一个地址,当其改变时是不会影响到原数据的,相同的是原数据的改变也不会影响数值的改变。
相关练习
LeetCode中相关的题目:
题目详细描述
子集
class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: n = len(nums) res = [] def dps(i,tmp): res.append(tmp) for j in range(i, n): dps(j + 1, tmp + [nums[j]]) dps(0, []) return res
|
子集II
class Solution: def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: res = [] n = len(nums) nums.sort() def dps(i, tmp): res.append(tmp) for j in range(i,n): if j > i and nums[j] == nums[j-1]: continue dps(j+1, tmp + [nums[j]]) dps(0, []) return res
|
全排列:将题目给定的数组划分成左右两个部分,左边表示已经填过的数,右边表示代填的数,在回溯的时候动态维护这个数组
class Solution: def permute(self, nums: List[int]) -> List[List[int]]: res = [] n = len(nums) def back(cur): if cur == n: res.append(nums[:]) return for i in range(cur ,n): nums[cur],nums[i] = nums[i],nums[cur] back(cur+1) nums[i],nums[cur] = nums[cur],nums[i] back(0) return res
|
全排列II:
class Solution: def permuteUnique(self, nums: List[int]) -> List[List[int]]: n = len(nums) nums.sort() res=[] mark = [0 for i in range(n)] def back(cur,t): if cur == n: res.append(t.copy()) return for i in range(n): if mark[i] == 1: continue if i>0 and nums[i]==nums[i-1] and mark[i-1] == 0: continue t.append(nums[i]) mark[i] = 1 back(cur+1,t) t.pop() mark[i] = 0 back(0,[]) return res
|