leetcode回溯算法

回溯算法在LeetCode刷题中频繁出现,常用于全排列、组合总和等题目。本文总结了回溯算法的基本思想和常见题目的解题套路,包括46.全排列、47.全排列 II、39.组合总和、40.组合总和 II、131.分割回文串和22.括号生成。并提供了关键解题技巧,如深拷贝、去重逻辑以及递归终止条件等。
摘要由CSDN通过智能技术生成

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

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

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

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

而其中针对backtracker,其核心思想为

def backtrack(...):
    for 选择 in 选择列表:
        做选择
        backtrack(...)
        撤销选择

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

目录

46. 全排列

47. 全排列 II

39. 组合总和

40. 组合总和 II

131. 分割回文串

22. 括号生成


 

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

131. 分割回文串

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        n = len(s)
        res = []
        def help(i,tmpList):
            if i == n:
                res.append(tmpList[:])
                return
            for j in range(i,n):
                if not s[i:j+1] == s[i:j+1][::-1]:
                    continue
                tmpList.append(s[i:j+1])
                help(j+1,tmpList)
                tmpList.pop()
        help(0,[])
        return res

22. 括号生成

做减法分别判断左侧和右侧括号的数量,当左右均为0的时候加入到结果列表中。

class Solution(object):
    def generateParenthesis(self, n):
        """
        :type n: int
        :rtype: List[str]
        """
        res = []
        cur_str = ''
        def dfs(string,l,r):
            if l == 0 and r == 0:
                res.append(string)
                return
            if r < l:
                return 
            if l > 0:
                dfs(string + '(',l-1,r)
            if r > 0:
                dfs(string + ')',l,r-1)
        dfs(cur_str,n,n)
        return res

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值