案例讲解DFS

1. 算法原理
深度优先搜索(DFS):从某个起点出发,依次遍历每个未访问的邻接点,对每一个可能的分支路径深入到不能再深入为止。如下图:
在这里插入图片描述

2. 案例1——机器人的运动范围
(1)题目描述
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
(2)思路
1)从坐标(0,0)开始,向右、向下开始递归;
2)行超出索引、列超出索引、已遍历、不满足k的条件结束递归;
3)满足条件的标记坐标,范围+1,继续向右,向下递归。
(3)代码

	/**
     * @param m,n : 行和列
     * @param k : 行数位之和(行拆分的每个数之和) + 列的数位之和(列拆分的每个数之和) <= k
     * @return 能行走的范围大小(格子数量)
     */
    int m,n,k;
    boolean[][] visited;
    public int movingCount(int m, int n, int k) {
        //标记走过的坐标
        boolean[][] visited = new boolean[m][n];
        this.visited = visited;
        this.m = m;
        this.n = n;
        this.k = k;
        return dfs(0,0,0,0);
    }

    /**
     * @param i,j :行和列
     * @param si,sj : 行(列)的数位之和
     * @return
     */
    public int dfs(int i,int j,int si,int sj){
        //终止条件 :行超出索引、列超出索引、已遍历、不满足k的条件
        if(i>=m || j>=n || visited[i][j]==true || si+sj>k)
            return 0;
        visited[i][j] = true;//已遍历
        //数位之和每逢进位会突变一次,进位时数位之和-8,没进位时数位之和+1
        int temp_si = (i + 1) % 10 == 0 ? si - 8 : si + 1;//行数位之和
        int temp_sj = (j + 1) % 10 == 0 ? sj - 8 : sj + 1;//列数位之和
        return 1+dfs(i+1,j,temp_si,sj) + dfs(i,j+1,si,temp_sj);//向右,向下遍历
    }

3. 案例2——矩阵中的路径
(1) 题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]

但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

(2) 思路
1)先在矩阵中找出第一个符合要求的字母,找到后进入递归;
2)标记访问过的元素,递归四个方向的,符合要求的递归下一个;
3)被标记的元素在访问完毕需要改回原值;
4) 找到包含所有字符的路径后,即找出的路径等于字符串长度时,返回true,否则返回false。
(3)代码

	/**
     * @param board 矩阵
     * @param word 要求的字符串
     */
    public boolean exist(char[][] board, String word) {
        char[] chars = word.toCharArray();
        for(int i=0;i<board.length;i++)
            for(int j=0;j<board[0].length;j++){
                if(board[i][j]==chars[0]){//找出第一个符合要求的
                    board[i][j]='/';//标记访问过
                    if(dfs(board,chars,i,j,1)){
                        return true;
                    }
                    board[i][j]=chars[0];//访问完毕需改回来
                }
            }
        return false;
    }

    /**
     * @param i,j 矩阵索引 
     * @param k 当前chars的索引
     */
    public boolean dfs(char[][] board,char[] chars,int i,int j,int k){
        //递归终止条件:找到路径
        if(k==chars.length)
            return true;
        int[] x = {1,-1,0,0};
        int[] y = {0,0,1,-1};
        //递归四个方向
        for(int p=0;p<4;p++){
            int ix = i+x[p];
            int jy = j+y[p];
            if(ix<board.length&&ix>=0&&jy<board[0].length&&jy>=0&&board[ix][jy]==chars[k]) {//符合要求,递归下一个
                board[ix][jy] = '/';//标记访问过
                if(dfs(board, chars, ix, jy, k + 1)){
                    return true;
                }
                board[ix][jy]=chars[k];//访问完毕需改回来
            }
        }
        return false;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值