剑指offer 12.13. 搜索与回溯算法(中等)(DFS)

12.

题目:

剑指 Offer 12. 矩阵中的路径icon-default.png?t=M0H8https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/


想法:从某点开始"走",上下左右都可以,但也有很多不可以,如 

        1.边界不可以

        2.走过的不可以

        3.和字符串不匹配的不可以

        带着这种想法写了三层循环,但发现不好判断走过的,也不好记录何时走下一个(因为设定的上下左右都试试,但可能上就可以了,下左右没走),后改成递归写法,递归掌握不熟练!

代码:

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words=word.toCharArray();
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[0].length;j++){
                //遍历起始点(题目中没有说一定从0,0开始搜索)
                if(findPath(board,words,i,j,0))
                    //若找到则返回true,否则查找下一个开头
                    return true;
            }
        }
        return false;
    }
    boolean findPath(char[][] board,char[] words,int i,int j,int c){
        if(i<0||j<0||i==board.length||j==board[0].length)
            //抵达边界返回false
            return false;
        if(board[i][j]!=words[c])
            //当前值与字符串中不同
            return false;
        //即:如能走到下面的代码,则说明当前board[i][j]==words[c]
        if(c==words.length-1)
            //最后一个c也匹配,即全部能够匹配
            return true;
        //访问过设为空,用于下次检查不重复访问
        board[i][j]='\0';
        //访问周围四个 上下左右 只要有一个能走通就行 所以是或
        boolean res=findPath(board,words,i-1,j,c+1)||
                    findPath(board,words,i+1,j,c+1)||
                    findPath(board,words,i,j-1,c+1)||
                    findPath(board,words,i,j+1,c+1);
        //还需重置board[i][j],因为要从不同出发点多次搜索路径
        board[i][j]=words[c];
        return res;
    }
}

结果:

13.

题目:

剑指 Offer 13. 机器人的运动范围icon-default.png?t=M0H8https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/

 想法:感觉磁体和上题很相似,只是入参没有了数组,但想着还是需要记录某点是否访问过,则建立的flag二维数组,用递归作答(有返回值和无返回值两种).

不可走的情况:(可走时cnt++)

        1.边界不可以

        2.访问过不可以

        3.不满足k的条件不可以

代码:

//递归有返回值 flag是boolean
class Solution {
    public int movingCount(int m, int n, int k) {
        boolean[][] flag=new boolean[m][n];
        return findPath(flag,0,0,k);
    }
    private int findPath(boolean[][] flag,int i,int j,int k){
        if(i<0||j<0||i==flag.length||j==flag[0].length)
            //抵达边界返回false
            return 0;
        if(i%10+i/10+j%10+j/10>k)
            //当前值与字符串中不同
            return 0;
        if(flag[i][j])
            //已访问过 不要重复访问
            return 0;
        //该点设为已访问
        flag[i][j]=true;
        //访问周围四个 上下左右 只要有一个能走通就行 所以是或
        return 1+findPath(flag,i+1,j,k)  
                +findPath(flag,i,j+1,k);
                // 每次遍历时上和左已遍历故只遍历右和下即可
                // +findPath(flag,i-1,j,k)
                // +findPath(flag,i,j-1,k)

    }
}

//递归无返回值 flag是int
class Solution { 
    int cnt=0;
    public int movingCount(int m, int n, int k) {
        int[][] flag=new int[m][n];
        findPath(flag,0,0,k);
        return cnt;
    }
    void findPath(int[][] flag,int i,int j,int k){
        if(i<0||j<0||i==flag.length||j==flag[0].length)
            //抵达边界返回false
            return;
        if(i/10+i%10+j/10+j%10>k)
            //当前值与字符串中不同
            return;
        if(flag[i][j]==0)
            cnt++;
        else
            return;
        flag[i][j]=1;
        //访问周围四个 上下左右 只要有一个能走通就行 所以是或
        findPath(flag,i+1,j,k);
        findPath(flag,i,j+1,k);
    }
}

又学到了:给定一个数字n,计算该数的数位和的函数

private int bitSum(int n) {
    int sum = 0;
    while(n > 0) {
        sum += n % 10;
        n /= 10; 
    }
    return sum;
}

结果:

遍历上下左右:

只遍历右下:

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值