【递归、搜索与回溯算法】专题四——综合练习

文章目录

一、找出所有子集的异或总和再求和

Leetcode链接

一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0 。

例如,数组 [2,5,6] 的 异或总和 为 2 XOR 5 XOR 6 = 1 。

给你一个数组 nums ,请你求出 nums 中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。

注意:在本题中,元素 相同 的不同子集应 多次 计数。

数组 a 是数组 b 的一个 子集 的前提条件是:从 b 删除几个(也可能不删除)元素能够得到 a 。

示例 1:

输入:nums = [1,3]

输出:6

解释:[1,3] 共有 4 个子集:

  • 空子集的异或总和是 0 。

  • 1\] 的异或总和为 1 。

  • 1,3\] 的异或总和为 1 XOR 3 = 2 。 0 + 1 + 3 + 2 = 6

  • 利用上一专题中第二题的方法二进行解题,按本题要求我们记录path的方法应该是直接进行异或,这样每次进入dfs时不仅得到一个正确的子集,而且直接就是该子集的异或结果,这时直接令sum+=path;

  • 而本题恢复现场的方法值得注意,我们直接让path再次异或原来的元素就可以让该元素的痕迹消失,也就完成了恢复现场。

代码实现

java 复制代码
class Solution 
{
    int path;
    int sum;
    public int subsetXORSum(int[] nums) 
    {
        dfs(nums, 0);
        return sum;
    }
    public void dfs(int[] nums, int pos)
    {
        sum += path;
        for(int i = pos; i < nums.length; i++)
        {
            path ^= nums[i];
            dfs(nums, i + 1);
            path ^= nums[i]; // 恢复现场 
        }
    }
}

二、全排列 II

Leetcode链接

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

示例 1:

输入:nums = [1,1,2]

输出:

\[1,1,2\], \[1,2,1\], \[2,1,1\]

示例 2:

输入:nums = [1,2,3]

输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

解题思路

  • 全排列的进阶版,解题思路与原版一样,但是本题出现了重复的元素,我们需要处理一下可能会出现的重复的排列数。
  • 数组存在重复的数会导致在dfs的同一层(也就是全排列的同一位上的数)中若选择了相等的数就会导致重复的全排列,如果是不同层(也就是全排列的不同位)的选择就没事。
  • 那么我们可以先对nums排序,使重复的数字放在一块,便于后续操作。在同一层的选择会出现问题,那也就是在for循环中选择了相等的数,且这两个挨着的数中前者没有被使用过(used[i-1]==false),那么此时就判定不能再使用nums[i]了。

代码实现及解析

java 复制代码
class Solution {
    boolean[] used;
    List<List<Integer>> ret;
    List<Integer> path;
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);//先对nums排序,使重复的数字放在一块,便于后续操作
        int n=nums.length;
        used=new boolean[n];
        ret=new ArrayList<>();
        path=new ArrayList<>();
        dfs(nums);
        return ret;
    }
    void dfs(int[] nums){
        if(path.size()==nums.length){//得到一个全排列
            ret.add(new ArrayList<>(path));//拷贝副本
            return;
        }

        for(int i=0;i<nums.length;i++){//循环进行该位数字的不同选择

            //used[i]==false:该位数字不能被使用过 && 
            //(i==0:i为首位元素,就不用检查其重复性了 || 
            //nums[i]!=nums[i-1]:i不为首元素,则检查其是否与前一个元素相同||
            //used[i-1]==true:相同也没事,只要它俩不在同一层,也就是不代表同一位数)
            if(used[i]==false&&(i==0||nums[i]!=nums[i-1]||used[i-1]==true)){//条件满足才可以使用该数字
                path.add(nums[i]);
                used[i]=true;
                dfs(nums);
                path.remove(path.size()-1);
                used[i]=false;
            }

        }
    }
}

总结

  • 复习解题思路和代码注释

三、括号生成

Leetcode链接

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3

输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1

输出:["()"]

解题思路

  • 当n=3时,共6个位置(对应之前学过的几位数),每个位置有两种选择:左括号或右括号,正是进行了这样的一个思维转换才使得我们画出了决策图,进而使用dfs算法解题

决策图:

什么叫有效的括号组合?

满足两点:

  1. 左括号总数==右括号总数
  2. 从左开始到任意位置的区间内所得括号组合中左括号数量均>=右括号(很巧妙)
  • 只要满足以上两点,该括号组合一定是有效的,所以反过来只要在生成括号组合的过程中始终满足第二点,并且在最终使第一点成立就可得出有效的括号组合

代码实现及解析

java 复制代码
class Solution {
    List<String> ret;
    StringBuilder path;
    int leftNum,rightNum;//实时记录左、右括号数量
    int n;
    public List<String> generateParenthesis(int _n) {
        n=_n;
        ret=new ArrayList<>();
        path=new StringBuilder();
        dfs();
        return ret;
    }
    void dfs(){
        if(rightNum==n){//递归出口:当右括号数量已达上限,则说明我们已经得到一个有效括号组合(毕竟不合格的已经被剪枝剪掉了,leftNum且始终保持>=rightNum)
            ret.add(path.toString());
            return;
        }

        //一层递归的不同选择(if语句作为剪枝操作):
        if(leftNum<n){//当左括号数量未达上限,该位置可以选左括号
            path.append("("); leftNum++;
            dfs();
            path.deleteCharAt(path.length()-1);//恢复现场
            leftNum--;
        }
        if(rightNum<leftNum){//当rightNum仍不及leftNum(这样保持leftNum>=rightNum,可使括号组合一直为有效),该位置可选右括号
            path.append(")"); rightNum++;
            dfs();
            path.deleteCharAt(path.length()-1);
            rightNum--;
        }
    }
}

总结

  • 复习解题思路和代码注释

四、组合

Leetcode链接

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

解题思路

  • 该题与之前【子集】那题一样,所以使用dfs解题

  • 该题为【组合/子集】类问题,该种问题中通常会出现"(1,2)和(2,1)是一样的"这种特征,当我们使用之前的"多层递归代表不同数位,每层递归内多个选择代表单个数位上不同的选择"这种方法来解题时要注意(可以结合决策图思考):

java 复制代码
path.add(nums[i]);
//进入下一层递归:
dfs(i+1);//pos=i+1
//下一层递归时要从i+1位置开始进行选择(递归中的for循环要从pos开始),
//因为i+1位置之前的元素在之前的某个情况中已经枚举过了,
//这次还使用的话虽然顺序不同,但在子集问题中仍属重复(相当于是你不要管现在存在不存在,而是这种组合之前存在过了,那这次就不应该再枚举了)
  • 用以上这种思路来理解【子集】那题的方法二会更好

代码实现及解析

java 复制代码
class Solution {
    List<List<Integer>> ret;
    List<Integer> path;
    int n,k;
    public List<List<Integer>> combine(int _n, int _k) {
        n=_n; k=_k;
        ret=new ArrayList<>();
        path=new ArrayList<>();
        dfs(1);
        return ret;
    }
    void dfs(int pos){
        if(path.size()==k){//枚举了k个数就可以了
            ret.add(new ArrayList<>(path));
            return;
        }

        for(int i=pos;i<=n;i++){//该位置可以有pos~n这些选择
            path.add(i);
            dfs(i+1);//但为了不重复,下一个位置就要从i+1开始(如解题思路中所讲)
            path.remove(path.size()-1);
        }
    }
}

总结

  • 复习解题思路和后面两个代码注释

五、目标和

Leetcode链接

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3

输出:5

解释:一共有 5 种方法让最终目标和为 3 。

-1 + 1 + 1 + 1 + 1 = 3

+1 - 1 + 1 + 1 + 1 = 3

+1 + 1 - 1 + 1 + 1 = 3

+1 + 1 + 1 - 1 + 1 = 3

+1 + 1 + 1 + 1 - 1 = 3

解题思路

  • 我们这几次使用的暴搜(dfs)解题方法在这种题目上也可以应用,也就是针对于"做多次选择,每次选择都有多种选项"这种特征的题目,且本题的做法与之前【子集】那道题目针对于每个元素进行"选与不选"的抉择的做题方法有很大的相似之处,只不过本题是"针对于每个数选择:加还是减"。

代码实现及解析

java 复制代码
class Solution {
    int count;//记录有效表达式的数目
    int target;
    public int findTargetSumWays(int[] nums, int _target) {
        target=_target;
        dfs(nums,0,0);
        return count;
    }
    void dfs(int[] nums,int pos,int path){
        if(pos==nums.length){//pos到头了,完成了一次完整的表达式定义
            if(path==target) count++;//如果表达式结果path为目标值,则计数+1
            return;
        }

        //选择加法:
        dfs(nums,pos+1,path+nums[pos]);//在参数中更新path,并进行下一位数的选择,使用参数维护path,方便恢复现场操作

        //选择减法:
        dfs(nums,pos+1,path-nums[pos]);//在参数中更新path,并进行下一位数的选择
    }
}

总结

  • 复习解题思路
  • 这种单变量path(本题是做为记录表达式加和的变量)确实也适合使用参数进行传递并记录,方便恢复现场,不用再使用全局变量了,可以去代码里看一下这个操作

六、 组合总和

Leetcode链接

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

解题思路

方法一:

  • 想一下与【子集】那题的联系,【子集】那题是"某元素选与不选",该题是"某元素选几个(0个、1个、2个......)",因为本题允许同一个数字无限制重复被选取。

  • 记住组合/子集类题目的该种做法

方法一恢复现场放在下面(先看代码,不然不知道在说什么)的原因:

  • 这个恢复现场的做法不是为了更换本层的选择,而是为了回溯过去之后方便更换上一层dfs中的组合选择,由此与之前的做法不一样(以前都是恢复现场->进入下一个循环->由此而换一个属于本层的选择),可能一下子反应不过来。

方法二:

  • 使用的方法与【子集】那题的方法二是一样的:

第二种方法就是对于子集问题的结果我们可以发现其结果可以分类:不含有元素的(空集)、只包含1个元素的、包含两个元素的...

所以我们可以分组进行处理,0元素的、有一个元素的... ,但是代码实现不是想当然地写的,我们可以在dfs中用for循环对每个元素进行遍历,这样来做出不同的选择,但每固定一个数(pos位置)仍需要直接进入下一位数(pos+1)的dfs,而且dfs中的for循环是从形参pos开始的,不然会导致子集重复,这样我们发现每次进入dfs其实都是一个结果。

  • 记住组合/子集类题目的该种做法

代码实现及解析

方法一:

java 复制代码
//方法一:
class Solution {
    List<List<Integer>> ret;
    List<Integer> path;
    int[] nums;
    int target;
    public List<List<Integer>> combinationSum(int[] candidates, int _target) {
        nums=candidates;
        target=_target;
        ret=new ArrayList<>();
        path=new ArrayList<>();
        dfs(0,0);
        return ret;
    }

    void dfs(int pos,int sum){
        if(sum==target){//一旦该子集的和为目标值,就记录,并返回(再往下加就要>target了)
            ret.add(new ArrayList<>(path));
            return;
        }
        if(pos==nums.length||sum>target) return;//pos遍历到头了就必须要回溯了,或者sum都超过target了也没必要再往下递归了

        for(int i=0;(i*nums[pos]+sum)<=target;i++){//循环选择nums[pos]这个元素使用几个,直到>target
            if(i!=0) path.add(nums[pos]);
            //固定了一个数之后就去下一位:
            dfs(pos+1,sum+i*nums[pos]);
            //本来dfs回溯之后到了这里是要对path进行恢复现场的(将nums[pos]数量的使用更换),但是我们发现不恢复正好满足nums[pos]的数量递增1的要求
        }

        //但是要意识到for循环结束后,本层dfs就要结束而向上回溯了,也就是要回到上一个pos对nums[pos-1]位置元素的数量进行更换了,
        //那这个时候就要将残留下来的这些nums[pos]清除掉了
        for(int i=1;(i*nums[pos]+sum)<=target;i++){//但要注意i要从1开始,因为原来i==0的时候并没有add
            path.remove(path.size()-1);
        }

    }
}

方法二:

java 复制代码
//方法二:
class Solution {
    List<List<Integer>> ret;
    List<Integer> path;
    int[] nums;
    int target;
    public List<List<Integer>> combinationSum(int[] candidates, int _target) {
        nums=candidates;
        target=_target;
        ret=new ArrayList<>();
        path=new ArrayList<>();
        dfs(0,0);
        return ret;
    }

    void dfs(int pos,int sum){
        if(sum==target){//一旦该子集的和为目标值,就记录
            ret.add(new ArrayList<>(path));
            return;
        }
        if(pos==nums.length||sum>target) return;//pos遍历到头了就必须要回溯了,sum都超过target了也没必要再往下递归了

        for(int i=pos;i<nums.length;i++){
            path.add(nums[i]);
            dfs(i,sum+nums[i]);//这种子集问题,本来pos传参时应传i+1,但是该题允许一个元素无限制地使用,所以下一位数仍可使用i位置元素
            path.remove(path.size()-1);//恢复现场(sum作为参数,回溯过程中就自动恢复现场了)
        }
    }
}

总结

  • 可以先复习方法二的解题思路和代码注释,再复习方法一的解题思路和代码注释

七、N皇后

Leetcode链接

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

解题思路

  • 一般思路:对于每个Queen,它的位置有多种选择,使用dfs解题,不可放Queen放地方进行剪枝就行了,但是这样太麻烦了,每个Queen的放置都要遍历整个矩阵来寻找位置。

优化:

  • 我们发现按照规则所有Queen只能放在不同行上面,所有我们可以针对每一行进行多次选择,每次选择都有"该行中Queen应放在哪个位置"这样的多个选项,使用dfs解题。

  • 在dfs过程中我们面临一个问题:有些位置是不可以放置Queen的,所有我们要对这些位置进行标记,但是如果像以前一样做个check矩阵,遍历所有需标记的位置进行标记就又太麻烦了。

对于check数组的优化:

  • 规则是Queen位置的一整行(这个不用担心了因为dfs逻辑就是分行进行放置Queen的)、一整列都不可再放了,所以我们可以搞个col[n]数组,矩阵有几列,数组大小就为几,这样直接来标记一整列为不可放置。
  • 那对角线的标记也有好方法,将对角线放到数学的直角坐标系中可以发现其可分别表示为y=-x+b(副对角线)、y=x+b(主对角线),所以在同一对角线上的坐标的x+y(副对角线)或y-x(主对角线)相同(它们都等于b),所以以这样的方式直接将整个对角线标记。

(这个推导过程没有那么复杂,只是我用文字描述的话确实讲得比较多而已)

代码实现及解析

java 复制代码
class Solution {
    List<List<String>> ret;
    char[][] path;//以后对矩阵操作还是要建一个二维数组,这样好操作,转String什么的都好说,不使用这种二维数组会使对矩阵操作变得复杂
    int n;

    boolean[] checkCol;//column:列
    boolean[] checkDiag1;//主对角线(x+y=b)
    boolean[] checkDiag2;//副对角线(y-x=b)  diagonal:对角线
    public List<List<String>> solveNQueens(int _n) {
        ret=new ArrayList<>();
        n=_n;
        path=new char[n][n];
        checkCol=new boolean[n];
        checkDiag1=new boolean[2*n];
        checkDiag2=new boolean[2*n];
        //对棋盘path进行初始化:
        for(int i=0;i<n;i++){
            Arrays.fill(path[i],'.');
        }
        dfs(0);//从下标为0的那一行开始进行选择
        return ret;
    }

    void dfs(int row){
        if(row==n){//已对每一行Queen的位置进行了选择
            List<String> tmp=new ArrayList<>();
            //将字符型二维数组path进行转化:
            for(int i=0;i<n;i++){
                tmp.add(new String(path[i]));
            }
            ret.add(tmp);
            return;
        }

        for(int j=0;j<n;j++){
            if(!checkCol[j]&&!checkDiag1[row+j]&&!checkDiag2[j-row+n]){//该位置不能被标记为true
                path[row][j]='Q';
                checkCol[j]=checkDiag1[row+j]=checkDiag2[j-row+n]=true;
                dfs(row+1);//去下一行进行选择
                //恢复现场:
                path[row][j]='.';
                checkCol[j]=checkDiag1[row+j]=checkDiag2[j-row+n]=false;//注意Diag2(副对角线)的定位使用的是y-x+n,防止下标为负
            }
        }
    }
}

总结

  • 这种带矩阵的题目可能第一反应是使用bfs算法,但是要记住本题是符合"多次选择,每次都有多种选项"的特征的,所以使用dfs算法,接下来有几题也是这样的
  • 复习解题思路和代码注释

八、解数独

Leetcode链接

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则:

数字 1-9 在每一行只能出现一次。

数字 1-9 在每一列只能出现一次。

数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。


解题思路

  • 跟上题相似,使用dfs解题,对每个空格进行选择,每个空格有多个选项

那么本题的重点还是如何剪枝了:

  • 行和列像上题一样,搞个数组去定位每行、每列就行,不过本题还需标识哪行哪列的具体到哪一个数不能放置了,所以我们将数组的维度升高,变为二维数组,这样既可定位到行、列,又可以定位到具体的数
  • 而题目中要求的大方格的标记方法也简单,将每个大方格整体像二维数组那样进行下标的标记(0、1、2),然后对每个小方格的坐标进行计算便可得到大方格的坐标:(x/3,y/3),那么像上面那样我们也需定位到具体的数,所以将check大方格的数组定义为三维数组即可

代码实现及解析

java 复制代码
class Solution {
    boolean[][] checkRow,checkCol;
    boolean[][][] checkGrid;//检查大方格内是否有重复的数字
    public void solveSudoku(char[][] board) {
        checkRow=new boolean[9][10];
        checkCol=new boolean[9][10];
        checkGrid=new boolean[3][3][10];//单个一维数组的大小扩展为10是为了使其下标与数字适配

        //初始化check表:
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]!='.'){//遇到数字就将其行、列、大方格内的对应状态标记
                    int num=board[i][j]-'0';
                    checkRow[i][num]=checkCol[j][num]=checkGrid[i/3][j/3][num]=true;
                }
            }
        }
        dfs(board);
    }
    boolean dfs(char[][] board){
        /*
        对下面两个最外层for循环的解释:dfs进来就是要对一个位置进行数字放置的多种选择的,
        但由题可得该位置上可能已经就有数字了,所以我们进入dfs之后重新遍历一遍矩阵,直到遇到第一个空格
        我们再在这个位置上进行填写。

        也可以进dfs后直接进行判断:是空格就填写,不是就直接对坐标传参(pos)去下一层dfs像以前一样,
        但是在这样的二维矩阵中i、j可不是一直++的,我们要控制i、j的正确走向是很麻烦的,所以不建议这样写
        而且会多出来函数栈帧的开销
        */
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]=='.'){//此时找到了一个空白位置,可以对此位置进行数字放置的多种选择
                    for(int num=1;num<=9;num++){
                        if(!checkRow[i][num]&&!checkCol[j][num]&&!checkGrid[i/3][j/3][num]){
                            board[i][j]=(char)(num+'0');
                            checkRow[i][num]=checkCol[j][num]=checkGrid[i/3][j/3][num]=true;
                            if(dfs(board)) return true;//如果dfs返回了true,说明已经将所有位置都已放上了合适的数,就不要再去下面更改此次的选择而去换其他的数尝试了,直接return true

                            //恢复现场(然后进入下一层循环去更改此次的选择而去换其他的数尝试了):
                            board[i][j]='.';
                            checkRow[i][num]=checkCol[j][num]=checkGrid[i/3][j/3][num]=false;
                        }

                    }
                    //for循环结束了,说明这个位置压根就找不到一个合适的数放入,
                    //如果能找到合适数字填入该位置,那就会一直在里面dfs下去,直到将所有位置填完而解决此数独问题

                    //直接返回并给个失败的信号,不要再往下一个位置继续尝试了(而是回到上一个位置换一个数尝试):
                    return false;

                }
            }
        }
        return true;//最外层的两个大循环都结束了,说明此次遍历了所有的位置都不是空格(也就是已将所有位置都放上了合适的数了),直接给个成功的信号,回溯回去之后不要再换数字去尝试了
    }
}

总结

  • 复习解题思路和代码注释

九、单词搜索

Leetcode链接

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

解题思路

  • 读完题目就知道是使用dfs解题,只不过本题要寻找不同的合适的起点进行尝试,那就遍历矩阵一个一个找呗
  • 一步一步地在矩阵中走,每走一步之后(肯定不是瞎走,哪个位置与字母匹配才去哪)下一步就有四个放向的不同选择。但是千万不要以为是不同的字母代表不同次的选择,用个pos来标记匹配到了哪个字母就行

代码实现及解析

java 复制代码
class Solution {
    boolean[][] visited;
    int m,n;
    char[] word;
    //偏移量数组:
    int[] dx={0,0,1,-1};
    int[] dy={1,-1,0,0};
    public boolean exist(char[][] board, String _word) {
        m=board.length;
        n=board[0].length;
        visited=new boolean[m][n];
        word=_word.toCharArray();
        //遍历矩阵来寻找所有合适的起点(与第一个字母匹配的位置),从该起点开始搜索,使用dfs进行字母的一一匹配
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(board[i][j]==word[0]){
                    visited[i][j]=true;
                    if(dfs(board,i,j,1)) return true;//如果这个起点的尝试已成功了,就不用换其他起点尝试了
                    visited[i][j]=false;//恢复现场,选择下一个起点进行尝试
                }
            }
        }
        return false;//以所有起点开始的尝试均失败,不存在该单词
    }
    boolean dfs(char[][] board,int i,int j,int pos){
        if(pos==word.length){
            return true;
        }

        for(int k=0;k<4;k++){//尝试四个方向的路径
            int x=i+dx[k],y=j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&!visited[x][y]&&board[x][y]==word[pos]){
                visited[x][y]=true;
                if(dfs(board,x,y,pos+1)) return true;//如果此次的路径尝试已成功了,就不用换其他路径尝试了
                visited[x][y]=false;//恢复现场,换其他路径尝试
            }
        }
        return false;//四个方向都失败,所以该位置不行,回溯上去换路径
    }
}

总结

  • 复习解题思路
  • 给dfs设置返回值从而达到剪枝的目的的技巧应熟记,也就是当此次的路径尝试已经成功/失败(收到了dfs的返回值)就直接停止进行其他的dfs尝试,达到剪枝的目的(如果这句话不太理解在说什么就去结合代码思考)
相关推荐
北顾笙9802 小时前
day26-数据结构力扣
数据结构·算法·leetcode
德索精密工业-胡工3 小时前
M12连接器的增强技术:在高电磁干扰的车间里它是如何“活下来”的?
算法
ZenosDoron3 小时前
函数形参传数组
java·jvm·算法
极客天成ScaleFlash3 小时前
极客天成 NVFile 存算融合解决方案
算法·数据挖掘
Reisentyan3 小时前
[杭电春季联赛5]1004 赛马
算法
雨墨✘3 小时前
基于比较的三种排序算法:插入排序、合并排序和快排序
数据结构·算法·排序算法
故事和你913 小时前
洛谷-数据结构1-2-二叉树1
开发语言·数据结构·c++·算法·leetcode·动态规划·图论
xu_wenming3 小时前
手写数字识别项目教程
网络·算法
_日拱一卒3 小时前
LeetCode:19删除链表的倒数第N个节点
算法·leetcode·链表