【乱杀图解算法】48.旋转图像(旋转矩阵)

282 阅读3分钟

理解题意

来,先看题。

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

刷题不看题,做了也白做。我们来简单提炼一下题目关键信息:

  1. N*N矩阵,说明是个标标准准的正方形
  2. 不占用额外的内存空间,所以要求你原地修改矩阵

目的?举例如下,先假设顺时针旋转90°

[
  [1,2,3],
  [4,5,6],
  [7,8,9]
]
// 变成
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

找规律

理清楚题目要干嘛之后,我们就开始找规律、找思路了

f5797341b01be3dabf81ad5cf162cd9.jpg

我们可以发现,旋转后的第一行是原矩阵第一列的倒序,第二行是第二列的倒序,以此类推到最后一行。

但统一能够发现的,都是横的行,变成竖的列

学过线性代数的同学应该记得,里面有个概念叫矩阵的转置

什么是转置呢,粗略地讲就是把横的变成竖的,如图

7c7e77b3f7a56b95b31467817920919.jpg

所以,我们可以先利用转置的特性,把我们拿到题目的矩阵转置一下:

[
  [1,2,3],
  [4,5,6],
  [7,8,9]
]
// 变成
[
  [1,4,7],
  [2,5,8],
  [3,6,9]
]

原来我根据转置的规律是这么写的:

let rotate_stand = function (matrix) {
    let temp;
    // 转置
    for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix.length; j++) {
            temp = matrix[j][i];
            matrix[j][i] = matrix[i][j];
            matrix[i][j] = temp;
        }
    }
}

输出如下:

image.png

然后我发现,第一次也就是第一行转置成第一列时,原来的矩阵已经改变了,在第二次转置的时候之所以不能输出正确的结果,正是因为第二次转置是基于第一次已经转置的矩阵进行的。

但其实,我们再认真观察一下矩阵转置的规律

可以发现,矩阵中左对角线上的数字位置是不变的,而左对角线两侧的数字交换位置

也就是说,以左对角线为轴,对称交换两侧数据

1fdbaaa6921a30dae3d8d9cd18090d4.jpg

那么到了for循环中,具体又该怎么找更细节处的规律呢

82cb3704cc9493bec4373c794542689.jpg

具体代码实现思路如下:

let rotate_stand = function (matrix) {
    let temp;
    // 转置
    for (let i = 0; i < matrix.length; i++) {
        for (let j = i + 1; j < matrix.length; j++) {
            temp = matrix[j][i];
            matrix[j][i] = matrix[i][j];
            matrix[i][j] = temp;
        }
    }
}

再拿转置后的矩阵和目标矩阵对比一下

[
  [1,4,7],
  [2,5,8],
  [3,6,9]
]
// 变成
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

诶,我们可以发现,这不就是左右对称嘛,你也可以理解为镜像

所以我们只需要再进行一轮镜像变化,即可得到最终的目标矩阵,变化的规律同上方法可以找到

具体代码实现如下:

// 原地修改
let rotate_stand = function (matrix) {
    let temp;
    // 转置
    for (let i = 0; i < matrix.length; i++) {
        for (let j = i + 1; j < matrix.length; j++) {
            temp = matrix[j][i];
            matrix[j][i] = matrix[i][j];
            matrix[i][j] = temp;
            console.log(matrix);
        }
    }
    // 镜像
    for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix.length / 2; j++) {
            temp = matrix[i][j];
            matrix[i][j] = matrix[i][matrix.length - j - 1];
            matrix[i][matrix.length - j - 1] = temp;
        }
    }
    return matrix;
}

完美AC~