回溯算法

江枫思渺然 提交于 2020-01-06 21:50:19

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解。显然,当需要枚举的时候,如果对每种情况都进行循环,那算法的复杂度要O(n^n)。因此,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

回溯算法是一种leetcode刷题过程中出现频率比较高的题目。

针对这种算法,有些大佬总结了一种套路模板如下:

def func(nums):
    n = len(nums)
    res = []
    ...
    def backtracker(*args):
        ...
    backtracker(*args)
    return res

这里针对出现的题目进行一个总结

目录

46. 全排列

47. 全排列 II

39. 组合总和

40. 组合总和 II


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

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!