四重优化,速看剑指 Offer 13. 机器人的运动范围

Posted 来老铁干了这碗代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四重优化,速看剑指 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



第一次解题

错误解法:直接遍历二维数组试图解题,发现出错,因为机器人无法越过障碍

class Solution {
    public int movingCount(int m, int n, int k) {
        int num1, num2, sum = 0;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                num1 = 0; num2 = 0;
                int ii = i, jj = j;
                while(ii != 0) { num1 += ii%10; ii/= 10; }
                while(jj != 0) { num2 += jj%10; jj/= 10; }
                if(num1 + num2 <= k) sum++;
                System.out.println(i + "  " + j + "  " + num1 + "  " + num2 + "  " + sum);
            }
        }

        return sum;
    }
}

第二次解题

仔细思考后发现,这是一道考查连通块的题,即连通(0,0)的点的个数。
于是用DFS解,如下:

static class Solution {
    boolean[][] vis;
    int sum;
    int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
    int[][] next;
    int mm, nn;

    public int movingCount(int m, int n, int k) {
        // 全局变量的定义
        vis = new boolean[m][n];
        sum = 1;    // (0,0)一定能被访问到
        kk = k;  mm = m; nn = n;
        next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};

        vis[0][0] = true;
        dfs(0, 0);
        return sum;
    }
    public void dfs(int x, int y) {
        // 终止条件
        if(x > mm || y > nn) return;

        // 回溯
        for(int i = 0; i < 4; i++) {
            int xx = x + next[i][0], yy = y + next[i][1];
            // 1、超界, continue
            if(xx < 0 || xx >= mm || yy < 0 || yy >= nn) continue;
            // 2、被访问过,continue
            if(vis[xx][yy]) continue;
            // 3、计算是否能到达
            int xx1 = xx, yy1 = yy;
            int num1 = 0, num2 = 0;
            while(xx1 != 0) { num1 += xx1%10; xx1 /= 10; }
            while(yy1 != 0) { num2 += yy1%10; yy1 /= 10; }
            if(num1 + num2 <= kk) {   // 符合
                vis[xx][yy] = true;
                sum++;
                dfs(xx, yy);
            }
        }
    }
}

第三次优化

解法2中考虑了m或n是100的情况,但即使m or n为100,k最大值也只能取到20,因此不满足条件。 因此只需考虑m or n是二位数的情况即可。

class Solution {
    boolean[][] vis;
    int sum;
    int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
    int[][] next;
    int mm, nn;

    public int movingCount(int m, int n, int k) {
        // 全局变量的定义
        vis = new boolean[m][n];
        sum = 1;    // (0,0)一定能被访问到
        kk = k;  mm = m; nn = n;
        next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};

        vis[0][0] = true;
        dfs(0, 0);
        return sum;
    }
    public void dfs(int x, int y) {
        // 终止条件
        if(x > mm || y > nn) return;

        // 回溯
        for(int i = 0; i < 4; i++) {
            int xx = x + next[i][0], yy = y + next[i][1];
            // 1、是否超界 or 是否满足条件, continue
            if(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;
            // 2、是否曾经走过这个点
            if(!vis[xx][yy]) {
                vis[xx][yy] = true;
                sum++;
                dfs(xx, yy);
            }
        }
    }
}

第四次优化

第三次优化中,考虑的机器人从上下左右四个方向走的问题,但仔细思考后发现:
由于从0,0开始,因此只考虑向右or向下走即可。

class Solution {
    boolean[][] vis;
    int sum;
    int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
    int[][] next;
    int mm, nn;

    public int movingCount(int m, int n, int k) {
        // 全局变量的定义
        vis = new boolean[m][n];
        sum = 1;    // (0,0)一定能被访问到
        kk = k;  mm = m; nn = n;
        next = new int[][]{{1,0}, {0,1}};

        vis[0][0] = true;
        dfs(0, 0);
        return sum;
    }
    public void dfs(int x, int y) {
        // 终止条件
        if(x > mm || y > nn) return;

        // 回溯
        for(int i = 0; i < 2; i++) {
            int xx = x + next[i][0], yy = y + next[i][1];
            // 1、是否超界 or 是否满足条件, continue
            if(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;
            // 2、是否曾经走过这个点
            if(!vis[xx][yy]) {
                vis[xx][yy] = true;
                sum++;
                dfs(xx, yy);
            }
        }
    }
}

完整可运行代码

最后附上完整可运行代码

public class 剑指Offer13_机器人的运动范围 {
    // 错误解法: 因为无法越过障碍
    static class Solution_1 {
        public int movingCount(int m, int n, int k) {
            int num1, num2, sum = 0;
            for(int i = 0; i < m; i++) {
                for(int j = 0; j < n; j++) {
                    num1 = 0; num2 = 0;
                    int ii = i, jj = j;
                    while(ii != 0) { num1 += ii%10; ii/= 10; }
                    while(jj != 0) { num2 += jj%10; jj/= 10; }
                    if(num1 + num2 <= k) sum++;
                    System.out.println(i + "  " + j + "  " + num1 + "  " + num2 + "  " + sum);
                }
            }

            return sum;
        }
    }

    // 解法2:dfs:本质上是求连通块,就是连通(0,0)点的所有点的个数S
    static class Solution_2 {
        boolean[][] vis;
        int sum;
        int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
        int[][] next;
        int mm, nn;

        public int movingCount(int m, int n, int k) {
            // 全局变量的定义
            vis = new boolean[m][n];
            sum = 1;    // (0,0)一定能被访问到
            kk = k;  mm = m; nn = n;
            next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};

            vis[0][0] = true;
            dfs(0, 0);
            return sum;
        }
        public void dfs(int x, int y) {
            // 终止条件
            if(x > mm || y > nn) return;

            // 回溯
            for(int i = 0; i < 4; i++) {
                int xx = x + next[i][0], yy = y + next[i][1];
                // 1、超界, continue
                if(xx < 0 || xx >= mm || yy < 0 || yy >= nn) continue;
                // 2、被访问过,continue
                if(vis[xx][yy]) continue;
                // 3、计算是否能到达
                int xx1 = xx, yy1 = yy;
                int num1 = 0, num2 = 0;
                while(xx1 != 0) { num1 += xx1%10; xx1 /= 10; }
                while(yy1 != 0) { num2 += yy1%10; yy1 /= 10; }
                if(num1 + num2 <= kk) {   // 符合
                    vis[xx][yy] = true;
                    sum++;
                    dfs(xx, yy);
                }
            }
        }
    }

    // 解法2中考虑的m或n是100的情况,但即使m or n为100,k最大值也只能取到20,因此不满足条件。  因此只需考虑m or n是二位数的情况即可。
    static class Solution_3 {
        boolean[][] vis;
        int sum;
        int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
        int[][] next;
        int mm, nn;

        public int movingCount(int m, int n, int k) {
            // 全局变量的定义
            vis = new boolean[m][n];
            sum = 1;    // (0,0)一定能被访问到
            kk = k;  mm = m; nn = n;
            next = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};

            vis[0][0] = true;
            dfs(0, 0);
            return sum;
        }
        public void dfs(int x, int y) {
            // 终止条件
            if(x > mm || y > nn) return;

            // 回溯
            for(int i = 0; i < 4; i++) {
                int xx = x + next[i][0], yy = y + next[i][1];
                // 1、是否超界 or 是否满足条件, continue
                if(xx < 0 || xx >= mm || yy < 0 || yy >= nn || (xx%10 + xx/10 + yy%10 + yy/10 > kk)) continue;
                // 2、是否曾经走过这个点
                if(!vis[xx][yy]) {
                    vis[xx][yy] = true;
                    sum++;
                    dfs(xx, yy);
                }
            }
        }
    }

    // 解法4:由于从0,0开始,因此只考虑向右or向下走即可。
    static class Solution_4 {
        boolean[][] vis;
        int sum;
        int kk; // 代替k,定义全局变量,可以为dfs方法减少一个参数
        int[][] next;
        int mm, nn;

        public int movingCount(int m, int n, int k) {
            // 全局变量的定义
            vis = new boolean[m][n];
            sum = 1;    // (0,0)一定能被访问到
            kk = k;  mm = m; nn = n;
            next = new int[][]{{1,0以上是关于四重优化,速看剑指 Offer 13. 机器人的运动范围的主要内容,如果未能解决你的问题,请参考以下文章

剑指 Offer(C++版本)系列:剑指 Offer 13 机器人的运动范围

剑指 Offer(C++版本)系列:剑指 Offer 13 机器人的运动范围

剑指 Offer(C++版本)系列:剑指 Offer 13 机器人的运动范围

剑指 Offer(C++版本)系列:剑指 Offer 13 机器人的运动范围

剑指offer--13机器人运动范围

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