LeetCode 机器人的活动范围

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof

很明显,这一道题考查的是深度优先搜索/广度优先搜索。
方法一:深度优先搜索(通过栈来实现)
1、定义一个栈
2、将当前位置压入栈中
3、当栈不为空的时候,不断获取栈顶元素,判断从栈顶元素开始走的下一步位置是否可以走,如果可以,那么就将这个位置压入栈中,否则,如果所有的下一步位置都不可以走,就从这个栈中跳出栈顶元素
如何判断栈顶元素的下一步是否可以走呢?题目中已经明显给出了要求,不可以移动到方格外,也不能进行行坐标和列坐标的数位之和大于k,同时我们已经走过的位置同样不可以走,基于此,我们判断下一步位置是否可以走。

如果这个位置不可以走,我们如何调整走向呢?我们将定义两个二维数组,move_x,move_y,并且长度是2,并且move_x的初始值为{0,1},move_y的初始值为{1,0},因为题目是从[0,0]到[m - 1,n - 1],所以我们定义它移动的方向是右,下两个方向,每一次调整位置,都是在栈顶元素的基础上进行调整位置的
4、重复上述操作,直到栈为空。

对应的代码:

class Solution {
    //由于题目要求是从下标[0,0]到达[m - 1,n - 1],那么就说明了只要2个方向即可实现
    int[] move_x = new int[]{0,1};
    int[] move_y = new int[]{1,0};
    Stack<int[]> stack = new Stack<int[]>();//栈的泛型是一个数组类型,存放的是当前位置的横坐标和纵坐标
    //利用深度优先搜索实现
    public int movingCount(int m, int n, int k) {
         if(k == 0)
             return 1;//如果k为0,那么只有[0,0]这个位置可以满足,所以直接返回1
         int[][] route = new int[m][n]; //标记当前位置是否已经走过了
         int arr[];
         int i,x,y,a,b,result; //x,y表示机器人当前的位置,a,b表示机器人的下一步位置
         boolean flag ; //判断机器人的下一步位置是否可以走
         stack.push(new int[]{0,0});
         result = 1;
         route[0][0] = 1;//值为1表示已经走过了
         while(!stack.empty()){
             //当栈不为空时,获取栈顶节点
              flag = false;
              arr = stack.peek();
              x = arr[0];
              y = arr[1];
              for(i = 0; i < 2; i++){
                 a = x + move_x[i];
                 b = y + move_y[i];
                 if(a < 0 || a >= m || b < 0 || b >= n || route[a][b] == 1) //如果下一步发生了越界或者已经走过了,直接跳过,执行i++
                   continue;
                 else{
                 /*否则我们需要讨论这个位置的坐标各个数字之和是否大于k,如
                 果是,那么直接标记这一步已经走过了,这样下一次来的时候不
                 需要再判断这一个位置了,否则,就将这个位置压入到栈中
                 */
                     route[a][b] = 1; 
                     if(get(a) + get(b) <= k){
                        stack.push(new int[]{a,b});
                        flag = true;
                        result++;
                        break;

                     }  
                 }
              }
              if(!flag) //如果当前栈顶元素的下一个位置都不可以走,那么就将这个栈顶元素从栈中跳出
                stack.pop();
         }
         return result;
         
    }
    public int get(int num){
    //获取num这个数的各个数位的和
        int sum = 0;
        while(num != 0){
            sum += num % 10;
            num /= 10;
        }
        return sum;
    }
}

在这里插入图片描述
方法二:通过递归的方式实现深度优先搜索

class Solution {
    //由于题目要求是从下标[0,0]到达[m - 1,n - 1],那么就说明了只要2个方向即可实现
    int[] move_x = new int[]{0,1};
    int[] move_y = new int[]{1,0};
    int[][] route;  //标记当前位置是否已经走过了
    int result = 0;
    public int movingCount(int m, int n, int k) {
         if(k == 0)
             return 1;//如果k为0,那么只有[0,0]这个位置可以满足,所以直接返回1
         route = new int[m][n];
         getResult(0,0,m,n,k);
         return result;
    }
    public void getResult(int x,int y,int m,int n,int k){
        result++;
        route[x][y] = 1;//标记当前位置已经访问过了
        int a,b,i;//a,b表示当前位置的下一步位置
        for(i = 0; i < 2; i++){
           //获取下一步位置
            a = x + move_x[i];
            b = y + move_y[i];
            if(a < 0 || a >= m || b < 0 || b >= n || route[a][b] == 1){
                continue;//如果当前这个位置发生了越界,或者已经走过了
            }else if(get(a) + get(b) > k){
                route[a][b] = 1; //下一步位置虽然没有越界,但是各个数位之和大于k,那么标记这一步走过了,下一次就可以不用走这一步了
                continue;
            }
            getResult(a,b,m,n,k);//如果下一步可以走,那么就进入递归
        }

    }
    public int get(int num){
    //获取num这个数的各个数位的和
        int sum = 0;
        while(num != 0){
            sum += num % 10;
            num /= 10;
        }
        return sum;
    }
}

运行结果:
在这里插入图片描述
很奇怪的是,我们使用递归的时候,必然需要考虑的就是递归结束的条件,但是我们这里进行递归的时候却没有使用,这是为什么呢?我们可以通过观察一下for循环里面的判断语句,如果当前位置的下一步位置是可以走的,才可以进行递归,那么当最后一次递归的时候,所有的位置都已经走过了,从而使得程序退出的是for循环,来结束递归

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值