13.机器人的运动范围

13 机器人的运动范围

1 题目描述

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

2 题目分析

​ 同样的二维数组的遍历问题,考虑回溯法解决。具体步骤:

1. 创建visited[m][n]数组标记是否访问过;
2. movingCountCore(m, n, k, 0, 0, visited)表示从(0, 0)出发可以到达的格子
3. 用check(m, n, k, row, col, visited)表示能否进入(row,col),能的话标记visited,更新count = 1 + movingCountCore(m,n,k,row-1,col,visited)...上下左右。
4. 返回count
check函数具体实现条件:没有越界,没有被访问,数位和没超过k。

3 代码

public static int movingCount1(int m, int n, int k) {
    boolean[][] visited = new boolean[m][n];

    return movingCountCore(m, n, 0, 0, k, visited);
}

private static int movingCountCore(int m, int n, int i, int j, int k, boolean[][] visited) {
    // 检查当前节点是否可达
    int count = 0;
    if (check(m, n, i, j, k, visited)) {
        visited[i][j] = true;
        count = 1 + movingCountCore(m, n, i + 1, j, k, visited)
            + movingCountCore(m, n, i - 1, j, k, visited)
            + movingCountCore(m, n, i, j + 1, k, visited)
            + movingCountCore(m, n, i, j - 1, k, visited);
    }
    return count;
}

private static boolean check(int m, int n, int i, int j, int k, boolean[][] visited) {
    if (i >= 0 && i < m && j >= 0 && j < n && !visited[i][j] && (digitCount(i) + digitCount(j)) <= k) {
        return true;
    }else
    {
        return false;
    }
}

private static int digitCount(int num) {
    int digitCount = 0;
    while (num > 0) {
        digitCount += num % 10;
        num = num / 10;
    }
    return digitCount;
}

4 优化

​ 在搜索过程中可以将搜索方法缩减为向下和向右,而不必向上和向左,因为随着k的增加,新的区域都可以从上方或左方到达。因此我们可以使用递推的做法来解决该题,即同样使用visited来标记,从左上方开始往下扫描数组进行判断当前节点是否可以从左方或者上方任意一边到达(即visit[i - 1] [j]和visit[i] [j - 1]只要有一个为true)即可。

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

    boolean[][] visited = new boolean[m][n];
    visited[0][0] = true;
    int ans = 1;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if ((i == 0 && j == 0) || digitCount(i) + digitCount(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];
            }

            ans += visited[i][j] ? 1 : 0;

        }
    }
    return ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值