【LeetCode刷题记录】14.旋转矩阵

278 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

题目来源:LeetCode-旋转矩阵

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 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]

]

二、思路分析:

思路一:

  1. 定义一个临时容器推演结果,然后整体拷贝。
  2. 按矩阵第一行思考,旋转后第一行变成了最后一列,每一行的顺序对应旋转后每一列的顺序。
  3. 同理推演每一行(也就是所有位置)将当前位置对应到旋转后的位置为temp[j][N - i - 1] = matrix[i][j]
  4. 按照对应关系推演每一个像素旋转后的位置并记录,遍历结束后将记录的位置拷贝回原数组。

思路二:

  1. 因为是正方形矩阵,所以旋转一个位置一定同时牵动了其它三个位置
  2. 根据方法一中的位置对应关系将当前位置带入,推出四个位置的变化关系
  3. 限定遍历范围,确保每一个位置都只旋转一次并覆盖到所有发生变化的位置
  4. 如果是偶数边长的矩阵,可以横竖分别对折平分成四个小正方形
  5. 如果是奇数边长,则排除中心位置(旋转后位置不变),按高比宽长一位(或者相反)的平分成四个小矩形
  6. 遍历完成后将数组返回

思路三:

从最外圈往内一圈圈旋转

三、AC 代码:

思路一:

class Solution {
    public void rotate(int[][] matrix) {
        int N = matrix.length;
        int[][] temp = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                temp[j][N - i - 1] = matrix[i][j];
            }
        }
        // 遍历将推演结果拷贝回原数组。
        for (int i = 0; i < N; i++) {
            System.arraycopy(temp[i], 0, matrix[i], 0, N);
        }
    }
}

思路二:

class Solution {
    public void rotate(int[][] matrix) {
        int N = matrix.length;
        // 外层循环遍历到中间位置,奇数边长包含中间位置。
        for (int i = 0; i < (N + 1) / 2; i++) {
            // 内层循环遍历到中间位置,奇数边长不包含中间位置。
            for (int j = 0; j < N / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[N - j - 1][i];
                matrix[N - j - 1][i] = matrix[N - i - 1][N - j - 1];
                matrix[N - i - 1][N - j - 1] = matrix[j][N - i - 1];
                matrix[j][N - i - 1] = temp;
            }
        }
    }
}

思路三:

    public void rotate(int[][] grid) {
        for (int currentRowOrColumnStartIndex = 0, currentRowOrColumnEndIndex = grid.length - 1; currentRowOrColumnStartIndex < currentRowOrColumnEndIndex; currentRowOrColumnStartIndex++, currentRowOrColumnEndIndex--) {
            for (int j = currentRowOrColumnStartIndex; j < currentRowOrColumnEndIndex; j++) {
                int tmp = grid[currentRowOrColumnStartIndex][j];
                grid[currentRowOrColumnStartIndex][j] = grid[currentRowOrColumnEndIndex - (j - currentRowOrColumnStartIndex)][currentRowOrColumnStartIndex];
                grid[currentRowOrColumnEndIndex - (j - currentRowOrColumnStartIndex)][currentRowOrColumnStartIndex] = grid[currentRowOrColumnEndIndex][currentRowOrColumnEndIndex - (j - currentRowOrColumnStartIndex)];
                grid[currentRowOrColumnEndIndex][currentRowOrColumnEndIndex - (j - currentRowOrColumnStartIndex)] = grid[j][currentRowOrColumnEndIndex];
                grid[j][currentRowOrColumnEndIndex] = tmp;
            }
        }
    }

四、总结:

  1. 在原地旋转的过程中,可以从最外圈开始,再从第二圈,如此往复即可。
  2. 最外圈的矩阵大小比第二圈首尾各多1个元素。
  3. 如果矩阵长度为奇数,最后一圈是一个单独元素,不需要旋转,所以需要旋转的圈数为原矩阵的长度对2整除即可。