算法训练#5:深度优先搜索

40 阅读1分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

矩阵中的路径

内容

image.png

思路

这道题若要使用深度优先搜索方法解决,就先要把路径的选择看作一棵不规则的n叉树(2n4nZ2\le n\le4且n\in\mathbb Z
举个例子,若A为起点,则第一步可以走的节点为BS,也就是说以A为根节点的求解树中,第二层的节点是BS,以此类推下去,我们可以得到一棵完整的求解树,那么若再以board的其他字符作为起点,我们最后可以得到一片求解森林,我们要做的,就是在这片求解森林中用深度优先方法遍历求解树,然后找到与word相同的解的路径。
由于单纯的dfs方式会出现超时情况,所以我们还需要加入剪枝步骤,主要需要剪掉以下枝节:

  1. 访问到以前走过的节点
  2. 访问到字符不符合word对应位置的节点

这样出来的求解树更加简洁,搜索效率更高

代码实现

class Solution {
    public boolean exist(char[][] board, String word) {
        int x=board.length;
        int y=board[0].length;
        char[] words=word.toCharArray();
        for(int i=0;i<x;i++){
            for(int j=0;j<y;j++){
                if(dfs(board,i,j,words,0))return true;
            }
        }
        return false;
    }
    public boolean dfs( char[][] board, int x, int y, char[] word, int label) {
        if (y >= board[0].length || x >= board.length || y < 0 || x < 0|| board[x][y] != word[label] )
            return false;
        if (label == word.length-1) return true;
        //将board对应位置设为\0,在再结合上面的判断条件,就不会出现访问到之前访问过的节点的情况了
        board[x][y]='\0';
        //这里使用短路与是因为正常分开4个dfs方法还是会出现超时情况,也可以用4个数组分别记下上下左右4个方向对应的坐标变化,用for循环遍历
        boolean flag=dfs( board, x, y + 1, word, label + 1) || dfs( board, x, y - 1, word, label + 1) || dfs( board, x + 1, y, word, label + 1)|| dfs(board, x - 1, y, word, label + 1);
        //注意遍历完之后一定要把赋值还原,不然会出bug
        board[x][y]=word[label];
        
        return flag;
    }
}

机器人的运动范围

内容

image.png

思路

同样是在矩阵中遍历,但与上一题的区别是这一题所需要找的东西不同,上一题只需要遍历到一条路径返回一个布尔类型的值就可以了,但是这里要求有步数的限制,以及需要把访问到的节点都记录下来(计数就行),同样的地方是不能访问已经访问过的节点。

代码实现

class Solution {
    public int cnt=0;
    public int max=0;
    public int movingCount(int m, int n, int k) {
        boolean[][] x=new boolean[m][n];
        max=k;
        bfs(x,0,0);
        return cnt;
    }
    //求数位和
    public int digitSum(int x){
        int ans=0;
        while(x>0){
            ans+=x%10;
            x/=10;
        }
        return ans;
    }
    //深度优先搜索
    public void bfs(boolean[][] b,int x,int y){
        //判断有没有出界或者到达次数限制
        if(x<0||y<0||x>b.length-1||y>b[0].length-1||b[x][y]||digitSum(x)+digitSum(y)>max) return;
        b[x][y]=true;
        cnt++;
        //四个方向都走一下
        bfs(b,x+1,y);
        bfs(b,x-1,y);
        bfs(b,x,y+1);
        bfs(b,x,y-1);
    }
}