首页 > 编程语言 >Day25 第七章 回溯算法part04 回溯终章

Day25 第七章 回溯算法part04 回溯终章

时间:2024-08-11 12:16:16浏览次数:10  
标签:used nums Day25 self part04 len dfs 回溯 path

目录

任务

491.递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

思路

根据题意,因为要求的就是和顺序有关的子序列,所以不能对原数组进行排序,那么此时就不能用之前的used的方法和i > start的方法去重了,因为这两种方法都需要对原数组进行排序。这里考虑用set横向剪枝。

  • 纵向剪枝 由于是递增的,纵向剪枝去掉不符合的情况,就是比较当前值nums[i]和其父节点值path[-1]。
  • 横向剪枝 局部变量set加入新增元素,在同一层级的循环中,如果已经有同样的元素,则新的这个节点剪枝,由于是局部变量,不需要显式回溯。
    总体逻辑: 取一个节点,下一次再剩余序列中取,递归进行,然后根据子序列至少两个元素,做收集操作。
class Solution:
    def __init__(self) -> None:
        self.path = []
        self.paths = []
    def findSubsequences(self, nums: List[int]) -> List[List[int]]:
        self.dfs(nums,0)
        return self.paths
    def dfs(self,nums,start):
        if len(self.path)>1:
            self.paths.append(self.path[:])
            
        size = len(nums)
        uset = set()
        for i in range(start,size):
            if (self.path and nums[i]< self.path[-1]): # 深入时根据条件剪枝(新节点的值小于上一个节点的值)
                continue
            if nums[i] in uset:
                continue
            
            uset.add(nums[i])    # 横向剪枝(去重) 由于求的就是有序子序列,不能排序然后像之前那样用 i > start去重,而用局部变量set去重,又由于是局部变量,所以不需要显式回溯,set中的元素表示该层用过的元素
            self.path.append(nums[i])
            self.dfs(nums,i+1)
            self.path.pop()

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

思路

由于全排列选了一个数后,其他的数都可以取,所以不是用start来进行递归驱动的。这里有两种思考的方法

  1. 考虑用used数组,表示已经使用的列表元素,每次都可以取没有使用的列表元素,直到某条路就已经处理完所有元素,这个条件可以用len(path)==len(nums)来表示
  2. 考虑用unKnownFirst哨兵的驱动方法,表示当前处理了元素的哨兵,它将原列表分为了两个部分,[0,unKnownFirst)表示已选取的部分,[unKnownFirst,size)表示为选取的部分,随着递归的进行,unKnownFirst最终等于size,即完成了一条路径的选取
# 方法1 used数组
class Solution:
    def __init__(self) -> None:
        self.path = []
        self.paths = []
        
    def permute(self, nums: List[int]) -> List[List[int]]:
        used = [False] * len(nums)
        self.dfs(nums,used)
        return self.paths
    def dfs(self,nums,used):
        if len(self.path) == len(nums):
            self.paths.append(self.path[:])
            return 
        
        for i in range(0,len(nums)):
            if used[i]:
                continue
            
            used[i] = True
            self.path.append(nums[i])
            self.dfs(nums,used)
            self.path.pop()
            used[i] = False
            
# 方法2 unKnownFirst哨兵
class Solution:
    def __init__(self) -> None:
        self.path = []
        self.paths = []
        
    def permute(self, nums: List[int]) -> List[List[int]]:
        self.dfs(nums,0)
        return self.paths
    def dfs(self,nums,unKnowFirst): # unKnowFirst 为当前第unKnowFirst的位置的值选哪个
        if unKnowFirst == len(nums):
            self.paths.append(self.path[:])
            return 
        
        for i in range(unKnowFirst,len(nums)):
            nums[i],nums[unKnowFirst] = nums[unKnowFirst],nums[i]
            self.path.append(nums[unKnowFirst])
            self.dfs(nums,unKnowFirst+1)
            self.path.pop()
            nums[i],nums[unKnowFirst] = nums[unKnowFirst],nums[i]

47.全排列II

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

思路

由于包含重复元素,且需要返回不重复的全排列,所以需要去重。想到了之前组合中的去重方法,使用used数组进行横向剪枝。

class Solution:
    def __init__(self) -> None:
        self.path = []
        self.paths = []
        self.used = []
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        self.used = [False] * len(nums)
        nums.sort()
        self.dfs(nums)
        return self.paths
    def dfs(self,nums):
        if un == len(nums):
            self.paths.append(self.path[:])
            return 
        
        for i in range(0,len(nums)):
            if self.used[i]:
                continue
            if i> 0 and nums[i] == nums[i-1] and self.used[i-1] == False:
                continue
            self.used[i] = True
            self.path.append(nums[i])
            self.dfs(nums)
            self.path.pop()
            self.used[i] =False

心得体会

暴力递归类的题目目前做过的类型如下:
组合: start 驱动,考虑进入下一层的时候start需要为多少,如下一个数在后续元素中选取。终止条件(收集信息)是到达需求的数量k,此时即为叶子节点,此时收集一条路径的信息,used数组或者i>start条件进行横向去重,注意去重之前要排序
子集: start 驱动,考虑进入下一层的时候start需要为多少,如下一个数在后续元素中选取,终止条件是任意节点,都将它包含的路径加入到最终结果中。递增子序列是一个类子集问题,由于不能排序所以横向剪枝采用局部变量set。
分割: 对比其他的问题相对抽象,start驱动,考虑进入下一层的时候start需要为多少,如下一个分割在后续索引中选取,终止条件为分割索引到达size。[start,i]一般表示该次分割的范围区间。
排列:used驱动,每次只要没选过都可以选。或者unKnownFirst驱动,每次选取的放在unKnownFirst,然后unKnownFirst+1驱动dfs。终止条件为排列完成,len(path)len(nums) 或者 unKnownFirstlen(nums) 去重方面,同前面问题使用used数组,注意去重前需要排序。

剩余题目有时间刷:
332.重新安排行程
51. N皇后
37. 解数独

标签:used,nums,Day25,self,part04,len,dfs,回溯,path
From: https://www.cnblogs.com/haohaoscnblogs/p/18353243

相关文章

  • 代码随想录day25 || 491 递增子序列,46 全排列, 47 全排列2
    491递增子序列funcfindSubsequences(nums[]int)[][]int{ //思路,在原数组上面找寻递增子序列,所以不能改变顺序, varpath[]int varres[][]int //nums=quicksort(nums) backtracking(nums,&path,&res,-200)//范围是【-100,100】,传入一个不在区间的数字就不会......
  • 实训day25(8.9)
    一、方法一指定pip从哪个源服务器下载和安装Python包pip3configsetglobal.index-url清华镜像站https://pypi.tuna.tsinghua.edu.cn/simple安装SQLAlchemyyum-yinstallsqlalchemy使用pip3安装pandas库pip3installpandas导入pandas作为pdimportpanda......
  • 回溯函数(算法)杂谈 -----可主动控制撤回逻辑处理的递归函数
    概述回溯,对接触了算法的人而言,并不陌生,其实严谨地说回溯函数就是递归函数,只不过在使用上,人们将它的一些细节抽离出来,进而演化出了所谓的回溯,在算法导论中,与其相关的被称为“回溯搜索算法”。回溯本质是递归的副产物,只要有递归调用就会有回溯。回溯法也经常和二叉树或N叉树......
  • Day24 第七章 回溯算法part03
    目录任务78.子集思路90.子集II思路93.复原IP地址思路心得体会任务78.子集给你一个整数数组nums,数组中的元素互不相同。返回该数组所有可能的子集(幂集)。解集不能包含重复的子集。你可以按任意顺序返回解集。思路和组合问题类似,思路是从序列中每次选一个,选的深度......
  • Day23 第七章 回溯算法part02
    目录任务39.组合总和思路40.组合总和II思路131.分割回文串思路心得体会任务39.组合总和给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些......
  • 回溯的简单辅助讲解
    回溯策略我个人其实把回溯看做递归的一个应用,回溯简单来讲就是用递归的方式深度遍历所有的可能,而在某些可能是一个解的时候,就记录,这目前看来和回溯两个字没啥关系,问题就在于,回溯可以解决一些需要我们回退元素并继续尝试的问题。刚才的概念里包含了两个关键词:“回退”,“尝试”。......
  • Python回溯算法
    回溯算法回溯算法是一种系统的搜索算法,用于解决诸如排列组合、子集生成、图的路径、棋盘问题等问题。其核心思想是通过递归尝试各种可能的解决方案,遇到不满足条件的解时则回退(回溯),继续尝试其他可能性,直到找到所有的解决方案或确认无解。主要步骤:选择路径:在当前步骤选择一个可......
  • C++回溯算法经典例题:四皇后问题
    问题简介:在一个4×4的棋盘上,任意两个皇后都不能处在同一行、同一列任意两个皇后都不能处在同一斜线上(主斜线、反斜线)。题目分析:1.假设第一个皇后在(1,1):    1)在x=3时会卡死            2)在x=4时会卡死        2.假设第一个皇后在(2,1): ......
  • Day 30 贪心算法 Part04
    452.用最少数量的箭引爆气球自己写没写出来,不过找到篇很好的题解,贪心想不到就是想不到,没办法。本以为自己的思路也是贪心,但就是做不出来。classSolution{publicintfindMinArrowShots(int[][]points){boolean[]visited=newboolean[points.length];......
  • Day15 二叉树Part2 初见回溯(二叉树相关)
    任务110.平衡二叉树给定一个二叉树,判断它是否是平衡二叉树思路典型的树形DP,每个节点向它的左右孩子收集信息,然后利用收集到的信息判断当前节点,最后再将信息传给上层。对于本题,每个节点要判断以自己为根的树是否是平衡二叉树,需要判断3个条件:自己的左子树是否平衡自己的右子......