Loading

Medium | 剑指 Offer 13. 机器人的运动范围 | 矩阵 + DFS递归遍历

剑指 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:

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

示例 2:

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

提示:

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

本题通过DFS遍历就就能解决。DFS遍历需要设置一个访问数组标志当前位置是否已经访问过。访问下一个位置时可以用一个4x2的数组来表示上下左右的四个方向int[][] dir = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};如果下一个位置可以访问, 就访问它, 不能访问或者访问过了就遍历下一个位置。

private int[][] dir = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
// 访问标志数组
private boolean[][] visit;
private int row;
private int colume;
// 本题的坐标各个位数之和的最大阈值
private int threshold;

public int movingCount(int m, int n, int k) {
    this.row = m;
    this.colume = n;
    this.threshold = k;
    visit = new boolean[m][n];
    // 开始暴力DFS遍历, 
    dfs(0, 0);
    int res = 0;
    // 此时DFS遍历完成, 所有能够访问的位置已经在visit数组打上了标记, 只需要统计数量即可
    for(int i = 0; i < row; i++) {
        for (int j = 0; j < colume; j++) {
            if (visit[i][j]) {
                res++;
            }
        }
    }
    return res;
}
// dfs遍历矩阵
public void dfs(int x, int y) {
    visit[x][y] = true;
   	// DFS遍历与当前位置相邻的几个位置, 这里只需要向右和向下即可, 不需要向上和向左, 因为是从左上角出发的
    // DFS本身是可以枚举每一种可能情况的
    for(int i = 1; i < 3; i++) {
        int newx = x + dir[i][0];
        int newy = y + dir[i][1];
        if (checkCanEntry(newx, newy)) {
            dfs(newx, newy);
        }
    }
}
// 判断是否能够访问:1. 下标是否越界 2. 是否已经访问过 3. 坐标位数之和是否超过阈值
public boolean checkCanEntry(int x, int y) {
    return x >= 0 && x < row && y >= 0 && y < colume && 
    !visit[x][y] && 
    getDigit(x) + getDigit(y) <= threshold;    
}

// 求某个数字的各个位数之和
public int getDigit(int x) {
    int sum = 0;
    while(x != 0) {
        sum += x % 10;
        x /= 10;
    }
    return sum;
}
posted @ 2021-01-15 11:12  反身而诚、  阅读(60)  评论(0编辑  收藏  举报