1041.困于环中的机器人 && 874.模拟行走的机器人 && 模拟行走的机器人 2 (三道机器人的模拟题)

共性

  1. 对于直接行走类的题,我们都可以用 int[][] dirs = new int[][]{{0,1}, {-1,0}, {0,-1}, {1,0}}; 来表示向 北 西 南 东 走一步
  2. 可以 int x = 0, y = 0, d = 0 xy 表示坐标,d表示方向,要和上面表示的方向对应
  3. 由于是对应的 d = 0 表示北 d = 1 表示西 d = 2 表示南 d = 3 表示东 即逆时针一圈
  4. 左转: d = (d+1) % 4 右转:d = ((d - 1) % 4 + 4) % 4 => d = (d + 3) % 4

1041.困于环中的机器人

经过多次指令 instructions 后,判断机器人是不是能回到原点。

解析:

  • 执行一次指令后能否回到原点 (0, 0) 不看方向
  • 执行一次指令后,方向是不是不朝北
class Solution {
    public boolean isRobotBounded(String instructions) {
        int x = 0, y = 0, d = 0; // d用来控制方向,d为0表示向北
        int[][] dirs = new int[][]{{0,1}, {-1,0}, {0,-1}, {1,0}};
        for(char c : instructions.toCharArray()){
            if(c == 'G'){
                x += dirs[d][0];
                y += dirs[d][1];
            }else if(c == 'L'){
                d = (d + 1) % 4; // 每次左转,d就能加1
            }else if(c == 'R'){
                d = ((d - 1) % 4 + 4) % 4; // 每次右转,d-1,但是为了让d在 0 - 4里面,就需要+4
                // d = (d + 3) % 4;
            }
        }
        return (x==0&&y==0) || d != 0;
    }
}

874.模拟行走的机器人

经过多次指令 commands 后,机器人离原点的最大欧式距离的平方,注意存在障碍物 obstacles ,有障碍物不能越过,只能停在前一个位置,但不影响后续指令

解析:

  • 利用字符串拼接的模式存储障碍物,以方便比较
  • 一次一步的走,有障碍物就停住
class Solution {
    public int robotSim(int[] commands, int[][] obstacles) {
        // 存障碍物,直接将 x y 存为String形式
        Set<String> set = new HashSet<>();
        for(int[] o : obstacles) set.add(o[0] + "," + o[1]);
        // 方向 南 北 西 东 ==> 要与d对应 0表示向北走一步 1西走 2南走 3东走
        int[][] dirs = new int[][]{{0, 1}, {-1, 0}, {0, -1}, {1, 0}};
        int ans = 0; 
        // x代表东西走,y代表南北走  d代表方向 0北 1西 2南 3东
        int x = 0, y = 0, d = 0; 
        for(int i = 0; i < commands.length; i++){
            if(commands[i] == -2){
                // 左转 顺时针转,方向都会 + 1
                // d = d == 3 ? 0 : d + 1;
                d = (d + 1) % 4; // 左转相当于方向+1
            }else if(commands[i] == -1){
                // 右转 逆时针转,方向都会 - 1
                // d = d == 0 ? 3 : d - 1;
                d = (d + 3) % 4; // 右转相当于左转3次
            }else{
                // 没有遇到障碍物会一直走,直到这一轮的步数走完
                // 有障碍物就不会再走一步
                while(commands[i] > 0 && !set.contains((x + dirs[d][0]) + "," + (y + dirs[d][1]))){
                    x += dirs[d][0];
                    y += dirs[d][1];
                    commands[i]--;
                }
                ans = Math.max(ans, x*x + y*y);
            }
        }
        return ans;
    }
}

模拟行走的机器人 2

在一个网格内行走,走到了边界就逆时针旋转90°,然后继续向前走,设置行走的方法函数。

解析:

  • 该题不用真的行走,只需要知道机器人的位置在哪里就行了
  • 需要单独判断一下 (0, 0) 的朝向问题,因为可能刚好走回来到这个点,就超南,如果没有移动过就超东
class Robot {
    // 前进的四个方向
    String[] ss = new String[]{"East", "North", "West", "South"};
    int w, h, loc; // loc :有效(取模后)移动步数
    boolean moved; // 记录是否经过移动,用于判断 (0, 0) 的方向
    public Robot(int width, int height) {
        w = width;
        h = height;
    }
    
    public void step(int num) {
        moved = true;
        loc += num; // 只用知道总步数就行了,因为他一直在转圈圈
        loc = loc % (2 * (w - 1) + 2 * (h - 1)); // 路程超过了一圈,直接取模,看位置在哪里就行了,不用真的走
    }
    
    public int[] getPos() {
        int[] info = move();
        return new int[]{info[0], info[1]};
    }

    public String getDir() {
        int[] info = move();
        // x y 代表方向, dir 代表朝向
        int x = info[0], y = info[1], dir = info[2];
        // (0, 0) 时, 当未移动过方向为 East, 移动过方向为 South (从上指过来)
        if(x == 0 && y == 0) return moved ? ss[3] : ss[0];
        return ss[dir];
    }

    int[] move(){
        if(loc <= w - 1){
            // 当移动的步数在[0, w - 1] 时,所在位置在外圈下方,方向为East
            return new int[]{loc, 0, 0};
        }else if(loc <= (w - 1) + (h - 1)){
            // 往右走到底,然后往上走,方向为:North
            return new int[]{w-1, loc - (w - 1), 1};
        }else if(loc <= 2 * (w - 1) + (h - 1)){
            // 往右走到底,然后往上走到底,又往左走,方向:West
            return new int[]{(w - 1) - (loc - ((w - 1) + (h - 1))), h - 1, 2};
        }else {
            // 最后一种情况是在左边做外圈,往下走
            return new int[]{0, (h - 1) - (loc - (2 * (w - 1) + (h - 1))), 3};
        }
    }  
}

你可能感兴趣的:(LeetCode,机器人,java,算法)