[2021校招必看之Java版《剑指offer》-66] 机器人的运动范围

1、题目描述

  【JZ66】地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
  知识点:数组,递归
  难度:☆☆

2、解题思路

  已知一个数字,求这个数字的数位之和,可以定义一个函数 add(n):
  1、定义一个变量 sum = 0;
  2、sum = sum + n%10 ,
  3、n = n / 10
  4、判断 n 是否为 0,是则返回 sum,不是则回到第 2 步。

  定义一个二维数组 mark[rows][cols] 用于标记每一个点的情况。0 表示未走过,1表示已走过。

  每走到一个坐标 (x, y) 分下面几步判断:
  1、越界判断:x < 0 || x >= rows || y < 0 || y >= cols ;
  2、未走判断:mark[x][y] != 1 ;
  3、阈值判断:add(x) + add(y) <= threshold

  若 (x, y) 通过上面三个判断,说明这个点是可以走的,设置 mark[x][y] = 1 ,然后往右、往下、往左、往上都递归走一步。

  最后统计 mark 里面 1 的个数就是可走格子的个数。

3、解题代码

package pers.klb.jzoffer.hard;

/**
 * @program: JzOffer2021
 * @description: 机器人的运动范围
 * @author: Meumax
 * @create: 2020-07-16 09:50
 **/
public class MovingCount {
    public int movingCount(int threshold, int rows, int cols) {
        int stepCount = 0;
        // 定义二位数组用来表示地图,没走过的地方为0,走过的地方为1
        // 初始化全部为0
        int[][] mark = new int[rows][cols];
        dfs(0, 0, rows, cols, threshold, mark);
        // 统计走过多少个格子
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                if (mark[i][j] == 1) {
                    stepCount++;
                }
            }
        }
        return stepCount;
    }

    private void dfs(int x, int y, int rows, int cols, int threshold, int[][] mark) {
        // x y 超出边界 或者 当前点已经走过就不再走了
        if (x < 0 || x >= rows || y < 0 || y >= cols || mark[x][y] == 1) {
            return;
        }

        // 当前位置不可走
        if (add(x) + add(y) > threshold) {
            return;
        }

        // 代码走到这里说明(x,y)可以走
        // 留下现在走过的痕迹
        mark[x][y] = 1;

        // 向右走
        dfs(x + 1, y, rows, cols, threshold, mark);
        // 向下走
        dfs(x, y + 1, rows, cols, threshold, mark);
        // 向左走
        dfs(x - 1, y, rows, cols, threshold, mark);
        // 向上走
        dfs(x, y - 1, rows, cols, threshold, mark);
    }

    /**
     * 计算数字的每一个位的和
     *
     * @param n 带计算数字
     * @return 和
     */
    private int add(int n) {
        int sum = 0;
        while (n != 0) {
            sum += n % 10;
            n /= 10;
        }
        return sum;
    }
}

  时间复杂度:O(mn), m,n为矩阵大小,每个元素最多访问过一次
  空间复杂度:O(mn)

4、解题心得

  本题难度较低,是经典的深度优先搜索遍历,通过对一个全局变量 mark 的不断修正,递归遍历来计算出可走格子的数量。在二叉树的搜索当中用的比较普遍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值