leetcode 旋转图像

167 阅读4分钟

给定一个 n × n 的二维矩阵表示一个图像。

将图像顺时针旋转 90 度。

说明:

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

示例 1:

给定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

原地旋转输入矩阵,使其变为:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

示例 2:

给定 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]
]

写这个我首先是去发现规律,发现可以通过交换,也就是: [0,0]->[0,3];[0,1]->[1,3];[0,2]->[2,3] ;发现转换的过程中只需要将原来的 y 的位置换成 x ,至于转换后的 y 也就是数组长度 - 当前行的位置,就像下面:

for(let i = 0; i < arr.length; i ++) {
	for (let j = 0; j < arr[0].length; j ++) {
    	// arr[j][arr.length - i] = arr[i][j]
    }
}

差不多这样就可以,当时我还在想,真的好容易,结果把代码写出来发现由于交换位置出现了在遍历第二遍的时候就出现了问题,所以这样做的前提是原来的数组没有发生改变;于是我就想到了深拷贝一个数组,然后操作完成以后赋值到传入的数组即可,但我不想这样干,因为题目要求只要操作传入的二维数组,所以我就只能使用其他的方式;于是我就想到了大学学习的矩阵,还有学习 canvas 的矩阵变换,于是我百度了一下,发现不是很容易,毕竟我已经忘光了大学知识;于是我就暂时放弃这种思路,又回过头来发现规律,最后没发现什么特别的规律,就知道旋转,根据这个我开始总结规律,如果是使用旋转的话,首先我得知道要旋转几下才能达到题目要求;然后考虑每一轮旋转要移动多少个元素,然后发现了下面的规律:

  • 旋转的圈数是数组长度的一半,向下取整;
  • 每一个圈旋转的次数是当前圈一条边元素个数 - 1 次;
  • 两个圈之前旋转的次数差为 2 ;
  • 当移动操作的过程中如果从左到右只需要 j 递增,i 不变;
  • 当移动操作的过程中如果从上到下只需要 i 递增,j 不变;以此类推得到其余的规律;

我得到的代码如下:

function rotate(arr) {
  // 保存四种规则
  let obj = {
    0: { x: 0, y: 1 },
    1: { x: 1, y: 0 },
    2: { x: 0, y: -1 },
    3: { x: -1, y: 0 },
  };
  // 紧挨着的两个圈差2,但第一个圈只和长度差1,所以这里先加1
  let len = arr.length + 1;
  // 这个转的层数
  for (let i = 0; i < Math.floor(arr.length / 2); i++) {
    // 每一圈都减去2
    len -= 2;
    // 每个圈要移动的次数
    for (let k = 0; k < len; k++) {
      let swap = arr[i][i];
      let m = i,
        n = i;
      // 每一次移动需要移动的所有元素
      for (let j = 0; j < len * 4; j++) {
        // 得到当前需要进行哪一种操作
        let a = obj[Math.floor(j / len)];
        // 进行移动操作
        let temp = arr[m + a.x][n + a.y];
        arr[m + a.x][n + a.y] = swap;
        swap = temp;
        m = m + a.x;
        n = n + a.y;
      }
    }
  }
  return arr;
}

不知道为啥总是觉得写得代码不好看,即便最后的确能通过;

看看官方的讲解,只不过官方的第二种方法我居然看不下去,主要是我都没认真计算给的公式:旋转图像

我比较喜欢第三种,第一种我考虑过了,需要开辟额外的空间,这里的空间取决于传进来的数组。第三种经过的两次变换既方便理解,写出来的代码也容易看懂。

感觉这个哥们硬核,花样百出:深拷贝 + 螺旋 + 旋转 + 翻转 + 队列(4行代码,6解法,超99%) ,感谢这个作者:小宇。

下次好好学习,把他们这些思路都学习一遍。


来源:力扣(LeetCode)