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

160 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

题目:给定一个mn列的网格,网格的坐标从[0, 0][m-1, n-1]。现有一个人从[0, 0]开始移动,每次可以上下左右移动一格,但不能越界,也不能进入行坐标和列坐标数位之和大于k的格子,例如,当k的值为18时,机器人可以进入网格[35, 37]但不能进入[35, 38],问最终机器人可以到达多少格子?

解题思路

看完题目随便模拟了一下,例如m=2n=1的情况,此时k=1,则可到达网格为:

X
XX

根据上面的思路,这题不就是找出网格内所有网格中符合数位和不大于k的网格吗,于是可得如下代码:

public int movingCount(int m, int n, int k) {
    int count = 0;
    for(int i=0;i<m;i++){
        int inneri = innerSum(i);
        for(int j=0;j<n;j++){
            int innerj = innerSum(j);
            if((inneri+innerj)>k) continue;
            count++;
        }
    }
    return count;
}

public int innerSum(int i){
    int p = i/100;
    int q = (i%100)/10;
    int r = i%10;
    return p+q+r;
}

很明显,题意理解错误!。。。。。。而之所以出现这个情况,是因为我们默认所有解都是可达的,但事实并不是所有解都可达,例如下面这幅图:

1649584904555.png

可以看到黄色区域就算满足条件也是不可达的,而上述计算时没有考虑这些,再看下面这幅图:

1649584965651.png

图片来源: 剑指 Offer 13. 机器人的运动范围( 回溯算法,DFS / BFS ,清晰图解)

有些不可达解转变成了可达解,而我们可以发现一个规律,如果一个网格是可达的,那么从这个网格向下和向右搜索,必然可以搜索到所有满足条件的解,而当遇到了不满足条件的解就不会继续向下或向右搜索,此时就避免计算哪些不可达解了,代码如下:

public int movingCount(int m, int n, int k) {
    boolean[][] visited = new boolean[m][n];
    return dfs(0, 0, m, n, visited, k);
}
public int innerSum(int i){
    int p = i/100;
    int q = (i%100)/10;
    int r = i%10;
    return p+q+r;
}

public int dfs(int i, int j, int m, int n, boolean[][] visited, int k){
    if(i>=m||j>=n||(innerSum(i)+innerSum(j)>k)||visited[i][j]) return 0;
    visited[i][j] = true;
    return 1+dfs(i+1, j, m, n, visited, k)+dfs(i, j+1, m, n, visited, k);
}