day 2: 1861. 旋转盒子

56 阅读3分钟

1861. 旋转盒子

给你一个 m x n 的字符矩阵 box ,它表示一个箱子的侧视图。箱子的每一个格子可能为:

  • '#' 表示石头
  • '*' 表示固定的障碍物
  • '.' 表示空位置

这个箱子被 顺时针旋转 90 度 ,由于重力原因,部分石头的位置会发生改变。每个石头会垂直掉落,直到它遇到障碍物,另一个石头或者箱子的底部。重力 不会 影响障碍物的位置,同时箱子旋转不会产生惯性 ,也就是说石头的水平位置不会发生改变。 题目保证初始时 box 中的石头要么在一个障碍物上,要么在另一个石头上,要么在箱子的底部。 请你返回一个_ _n x m的矩阵,表示按照上述旋转后,箱子内的结果。

1861. 旋转盒子.png

先将数组旋转 90 度,获得新数组,再进行后续处理。

int m = box.length; // 1
int n = box[0].length; // 3
char[][] res = new char[n][m]; // 3 * 1
for (int row = 0; row < m; row++) {
    for (int col = 0; col < n; col++) {
        res[col][m - 1 - row] = box[row][col];
    }
}

处理数据的过程,每一列从下往上遍历,需要记录当前可能会被放石头的位置,从下往上,

  • 如果是石头('#'),就把石头移到记录的位置;
  • 如果是障碍物('*'),就更新记录可能会被放石头的位置为它的上一行;
  • 如果是空位('.'),不进行处理。
for (int col = 0; col < m; col++) {  // 列
    int p = n - 1;
    for (int row = n - 1; row >= 0; row--) {  // 行
        switch (res[row][col]) {
            case '#':
                res[row][col] = '.';
                res[p][col] = '#';                
                p--;
                break;
            case '*':
                p = row - 1;
                break;
            default:
                break;
        }
    }
}

也可以先处理数据,再旋转

需要注意的地方(没错,就是我写的 bug):

  • 旋转 90°,可不是简单把行变成列,它是第一行变成了最后一列,以此类推,最后一行变成第一列。
  • 移动石头的过程,需要将原来石头的位置变成空位,不然石头可能会变多哟。
  • 上面一点中,至于先移石头还是先变空位,需要注意先后关系,每一列最后一个位置和障碍物上一行时,石头的位置可能没发生变化,后变空位石头就会变少。

完整代码:

class Solution {
    public char[][] rotateTheBox(char[][] box) {
        int m = box.length; // 1
        int n = box[0].length; // 3
        char[][] res = new char[n][m]; // 3 * 1
        for (int row = 0; row < m; row++) {
            for (int col = 0; col < n; col++) {
                res[col][m - 1 - row] = box[row][col];
            }
        }

        for (int col = 0; col < m; col++) {  // 列
            int p = n - 1;
            for (int row = n - 1; row >= 0; row--) {  // 行
                switch (res[row][col]) {
                    case '#':
                        if (p != row) { 
                            res[row][col] = '.';
                            res[p][col] = '#';
                        }
                        p--;
                        break;
                    case '*':
                        p = row - 1;
                        break;
                    default:
                        break;
                }
            }
        }

        return res;
    }
}

后记:

  1. switch 支持的数据类型

    • 基本数据类型:char,byte,short,int
    • 包装数据类型:Character,Byte,Short,Integer
    • 枚举类型:Enum
    • 字符串类型:String(JDK 7+ 开始支持)
  2. 多分支 if 和 switch 的选择

    1. switch 支持的数据类型的限制
    2. 代码简洁性
    3. switch 只能用于等于,if 范围更广
    4. switch 中不使用 break,可一直执行
    5. case 值判断方式,效率更高