【leetCode】 - 旋转矩阵

353 阅读1分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

题目

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

leetcode-cn.com/problems/ro…

从旋转矩阵出发

我们知道:

题目所求的90°旋转,事实上是

  • 行转列,列转行

例如:

1 2 3

4 5 6

7 8 9

->

7 4 1

8 5 2

9 6 3

发现没有,我们的123跑到最后一列去了

抛弃题目所给限制,我们通过这一结论,可以很快地通过辅助数组解决这个问题:

 public static void rotate(int[][] matrix){
        int n = matrix.length;
        int[][] tmp = new int[n][n];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                //我们将每一行的值,写到每一列上,第i行变成第(n-i)列
                tmp[j][n - i - 1] = matrix[i][j];
            }
        }
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                //直接赋值就可以了
                matrix[i][j] = tmp[i][j];
            }
        }
​
    }

但是这里有一个问题:

  • 我们用到了辅助矩阵

那么就不满足题目的限制了,我们需要使用若干个常数以及换一种思路,来解决这个问题。

实际上我们已经找到了映射的规则:

  • 行转列,列转行,也就是上面的:

    • 第i行变成第(n-i)列
  • 细细说来,就是:

    • (i,j)->(j,n-i)

那么根据这个映射规则,我们换一种思路:

  • 我们旋转一部分(通过映射实现),带动另外一部分转动,最后做到整体的旋转

对于循环的逻辑确定,我们通过以下的例子来确定:

1 2 3

4 5 6

7 8 9

因为我们只有 常数个数用于临时记录,那么我们最好是一次只替换一组数,如下:

1 2 3

4 5 6

7 8 9

因为它们在旋转之后,刚好各发生了一次移动,且刚好是下一个数:

7 2 1

4 5 6

9 8 3

而且根据这个规则,我们知道了: 在一行的循环中,我们只需要将这个过程进行到倒数第二个数就可以了。

同理,我们也能够知道:我们只需要进行一半的列循环,就可以了。

那么自然得出我们的解决方法:

public static void rotate(int[][] matrix) {
    int tmp1,tmp2;
    int col = matrix.length-1;
    for (int i = 0; i < matrix.length/2; i++) {
        for (int j = i; j < col-i; j++) {
            tmp1 = matrix[i][j];
            for (int k = 0; k < 4; k++) {
                int m = j,n = col-i;
                tmp2 = matrix[m][n];
                matrix[m][n] = tmp1;
                tmp1 = tmp2;
                i = m;
                j = n;
            }
        }
    }
}