剑指 Offer 13. 机器人的运动范围——广度优先搜索、递推

一、题目

地上有一个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。请问该机器人能够到达多少个格子?

二、题解1——递归实现

向四个方向搜索

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int dfsSolver(int startL,int startR,int m,int n,int k,int[][] visited){
    
    
        if(startL<0||startR<0||startL>=m||startR>=n||dig_num(startL)+dig_num(startR)>k||visited[startL][startR]==1){
    
    
            return 0;
        }
        visited[startL][startR]=1;
        return 1+dfsSolver(startL-1,startR,m,n,k,visited)+dfsSolver(startL+1,startR,m,n,k,visited)+dfsSolver(startL,startR-1,m,n,k,visited)+dfsSolver(startL,startR+1,m,n,k,visited);
    }

    public int movingCount(int m, int n, int k) {
    
    
        int[][] visited = new int[m][n];
        return dfsSolver(0,0,m,n,k,visited);
    }
}

题解须知

我们将行坐标和列坐标数位之和大于 k 的格子看作障碍物,那么这道题就是一道很传统的搜索题目,我们可以使用广度优先搜索或者深度优先搜索来解决它,本文选择使用广度优先搜索的方法来讲解。

那么如何计算一个数的数位之和呢?我们只需要对数 x 每次对 10 取余,就能知道数 x 的个位数是多少,然后再将 x 除 10,这个操作等价于将 x 的十进制数向右移一位,删除个位数(类似于二进制中的 >> 右移运算符),不断重复直到 x 为 0 时结束。

同时这道题还有一个隐藏的优化:我们在搜索的过程中搜索方向可以缩减为向右和向下,而不必再向上和向左进行搜索。如下图,我们展示了 16 * 16 的地图随着限制条件 k 的放大,可行方格的变化趋势,每个格子里的值为行坐标和列坐标的数位之和,蓝色方格代表非障碍方格,即其值小于等于当前的限制条件 k。我们可以发现随着限制条件 k 的增大,(0, 0) 所在的蓝色方格区域内新加入的非障碍方格都可以由上方或左方的格子移动一步得到。而其他不连通的蓝色方格区域会随着 k 的增大而连通,且连通的时候也是由上方或左方的格子移动一步得到,因此我们可以将我们的搜索方向缩减为向右或向下。

三、题解2——广度优先搜索

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int movingCount(int m, int n, int k) {
    
    
        if(k==0){
    
    
            return 1;
        }

        int[] dx = {
    
    1,0};
        int[] dy = {
    
    0,1};
        int[][] visited = new int[m][n];
        visited[0][0] = 1;
        Queue<int[]> queue = new LinkedList<int[]>();

        queue.add(new int[]{
    
    0,0});
        int res=1;
        while(!queue.isEmpty()){
    
    
            int[] cell = queue.poll();
            int x = cell[0];
            int y = cell[1];

            for(int i=0;i<2;i++){
    
    
                int tx = x+dx[i];
                int ty = y+dy[i];
                if(tx<0||tx>=m||ty<0||ty>=n||dig_num(tx)+dig_num(ty)>k||visited[tx][ty]==1){
    
    
                    continue;
                }
                queue.offer(new int[]{
    
    tx,ty});
                visited[tx][ty] = 1;
                res++;
            }
        }

        return res;


    }
}

四、递推

在这里插入图片描述

class Solution {
    
    

    public int dig_num(int target){
    
    
        int sum = 0;
        while(target>0){
    
    
            sum+=target%10;
            target/=10;
        }

        return sum;
    }

    public int movingCount(int m, int n, int k) {
    
    
        if(k==0){
    
    
            return 1;
        }

        int[][] visited = new int[m][n];
        visited[0][0] = 1;

        int res=1;
        for(int i=0;i<m;i++){
    
    
            for(int j=0;j<n;j++){
    
    
                if(i==0&&j==0||dig_num(i)+dig_num(j)>k){
    
    
                    continue;
                }
                if(i-1>=0){
    
    
                    visited[i][j]|=visited[i-1][j];
                }
                if(j-1>=0){
    
    
                    visited[i][j]|=visited[i][j-1];
                }
                res+=visited[i][j]==1? 1:0;
            }
        }

        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/Cxf2018/article/details/109586461