leetcode_48. 旋转图像

353 阅读1分钟

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。

题目链接: 48. 旋转图像

题目

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

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

示例 1

IMG

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2

IMG

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

代码模板

/**
 * @param {number[][]} matrix
 * @return {void} Do not return anything, modify matrix in-place instead.
 */
var rotate = function (matrix) {};

解法

看完题目后,你可能已经发现了这道题加重了三个字请不要

23.jpg

请不要使用另一个矩阵来旋转图像,不用矩阵?那我用二维数组不就行了?这就有点跑题了,这道题的二维矩阵在代码中的实现就是二维数组,所以它的言外之意就是不要使用额外的空间,需要你在原地修改这个二维数组,那如果用额外空间呢?那可操作性就多了

// 随便写了一个
var rotate = function (matrix) {
  const n = matrix.length; // 因为 n x n 矩阵
  const temp = new Array(n).fill(0).map(() => new Array(n).fill(0));
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      temp[j][n - i - 1] = matrix[i][j];
    }
  }
  return temp;
  // if [[1,2,3],[4,5,6],[7,8,9]]
  // will [[7,4,1],[8,5,2],[9,6,3]]
};

用这种肯定是不行的,因为 leetcode 上这道题是 void 没有返回值,它测试的时候是直接看你有没有修改传递进函数中参数的值(其实也有办法,就是重新遍历 matrix 并赋值),所以这道题难点就在原地 TP,那怎么做到呢?

额外辅助空间做不到不要紧,我们可以通过其中看到矩阵旋转 90° 的原理,原理如下

24.png

如果原地操作,那么 [1,2,3] 移过去的时候又怎么能不改变 [3,6,9] 的位置呢?

学过线性代数的家人们可能就知道了(我学过也没想出来),矩阵转置,就可以做到行列交换,这里帮大家复习一下线性代数,转置矩阵怎么求

[1,2,3]   [1,0,0]   [1,4,7]
[4,5,6] x [0,1,0] = [2,5,8]
[7,8,9]   [0,0,1]   [3,6,9]

原矩阵 x 大小为 n 的单位矩阵,其实就是一个对角线反转,能够帮助我们原地进行一个行列翻转,这个时候在来一次镜像操作就可以解决这道题目

[1,4,7]    [7,4,1]
[2,5,8] -> [8,5,2]
[3,6,9]    [9,6,3]

因此这道题的解法就是

var rotate = function (matrix) {
  const n = matrix.length;
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      const temp = matrix[i][j];
      matrix[i][j] = matrix[j][i];
      matrix[j][i] = temp;
    }
  }
  for(let i = 0; i < n; i++) {
    matrix[i].reverse();
  }
};
// leetcode 的解法只需反转一半,但这个已经足够了

总结

没想到 leetcode 还能看到关于线性代数的一部分内容,可惜当初的知识已经随时间流去了