13. 机器人的运动范围

剑指offer 13 机器人的运动范围

地上有一个mn列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k18时,机器人能够进入方格 [35, 37],因为3+5+3+7=18。但它不能进入方格[35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入: m = 2, n = 3, k = 1
输出: 3

示例 2:

输入: m = 3, n = 1, k = 0
输出: 1

提示:

1 <= n,m <= 100
0 <= k <= 20

解法一:深度优先搜索(DFS)

深度优先遍历(DFS),通过判断该坐标是否越界、该坐标是否访问过、该坐标数位之和是否大于k来判断机器人能否进入该格子,不管能否进入,都将该格子标记为已访问,且退出当前调用栈后,不用回退标记数组的状态,因为本身就是要访问完所有能够访问到的格子。如果机器人能够进入坐标为(x,y)的格子,而后再判断机器人能否进入该坐标相邻的4个格子,直到所有能遍历到的格子都遍历结束。

注意: 有些格子机器人是遍历不到的,如k=0时, 不管m,n多大,机器人只能访问到(0,0),(0,1),(1,0)三个坐标,且只能到达(0,0)一个坐标,无法通过访问到的(0,1)(1,0)扩散出去访问别的坐标,因为这两个坐标机器人无法到达,只是可以通过(0,0)访问到他们一次而已,即这里要区分访问到达是不同的含义。

如下图中3×2的方格,机器人从(0,0)开始移动,由于k=0,故访问了(0,1)后,数位之和大于0,回溯到上一级栈(0,0)处,继续换个方向移动,访问(1,0)后发现同样数位之和大于0,又回溯到(0,0)处,此时发现没有方向可以移动了,整个dfs结束。另外的三个坐标(1,1)、(2,0)(2,1)根本就没有访问过。

但若让k=2,则按照上述思路思考,机器人可以访问到所有格子,只是(2,1)无法到达而已,但可以通过(1,1)或者(2,0)访问到,只是由于(2,1)数位之和为3大于2,机器人无法到达

在这里插入图片描述

class Solution {
    
    
    private int count = 0;//count在递归中一直改变,故设置为成员变量

    public int movingCount(int m, int n, int k) {
    
    
        if(m < 0 || n < 0 ) return -1;
        boolean[][] isVisited = new boolean[m][n];//标记矩阵
        dfs(m,n,k,isVisited,0,0);
        return count;    
    }
    
    private void dfs(int m,int n,int k,boolean[][] isVisited,int x,int y){
    
    
        //坐标越界或者已经访问过,直接返回退出本次调用栈
        if(x < 0 || x >=m || y < 0 || y >= n || isVisited[x][y]) return ;
        isVisited[x][y] = true;//标记该坐标访问过了
        
        //当已经确认机器人可以进入该坐标之后,才需要从这坐标向四个方向扩散
        if(getSum(x,y) <= k){
    
    
            count++;//机器人可以进入该坐标,故计数加一,并从该坐标往四个方向扩散
            int[] dx = {
    
    -1,1,0,0};
            int[] dy = {
    
    0,0,-1,1};
            for(int i = 0;i < 4;i++){
    
    //按照左、右、上、下四个方向扩散访问
                int a = x + dx[i];
                int b = y + dy[i];
                dfs(m,n,k,isVisited,a,b);
            }
        }else{
    
    
            return ;//机器人无法到达该坐标,故直接退出本次调用栈,返回上一级调用栈
        }
    }

    //计算行坐标和列坐标的数位之和
    private int getSum(int x,int y){
    
    
        int res = 0;
        while(x > 0){
    
    
            res += x % 10;
            x /= 10;
        }
        while(y > 0){
    
    
            res += y % 10;
            y /= 10;
        }
        return res;
    }
}

在这里插入图片描述

解法二:广度优先搜索(BFS)

class Solution {
    
    
    private int count = 0;

    public int movingCount(int m, int n, int k) {
    
    
        if(m < 0 || n < 0 ) return -1;
        boolean[][] isVisited = new boolean[m][n];//标记矩阵
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{
    
    0,0});
        isVisited[0][0] = true;

        while(!queue.isEmpty()){
    
    
            int[] point = queue.poll();
            int x = point[0];
            int y = point[1];

            //当已经确认机器人可以进入该坐标之后,才需要从这坐标向四个方向扩散
            if(getSum(x,y) <= k){
    
    
                count++;//机器人可以进入该坐标,故计数加一,并从该坐标往四个方向扩散
                int[] dx = {
    
    -1,1,0,0};
                int[] dy = {
    
    0,0,-1,1};
                for(int i = 0;i < 4;i++){
    
    
                    int a = x + dx[i];
                    int b = y + dy[i];
                    //坐标没有越界并且还没有访问过
                    if(a >= 0 && a < m && b >= 0 && b < n && !isVisited[a][b]){
    
    
                        queue.add(new int[]{
    
    a,b});
                        isVisited[a][b] = true;
                    }
                }
            }
        }  
         return count;    
    }
    
   
    //计算行坐标和列坐标的数位之和
    private int getSum(int x,int y){
    
    
        int res = 0;
        while(x > 0){
    
    
            res += x % 10;
            x /= 10;
        }
        while(y > 0){
    
    
            res += y % 10;
            y /= 10;
        }
        return res;
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/YouMing_Li/article/details/114270397