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]
]
二、思路分析:
思路一:
- 定义一个临时容器推演结果,然后整体拷贝。
- 按矩阵第一行思考,旋转后第一行变成了最后一列,每一行的顺序对应旋转后每一列的顺序。
- 同理推演每一行(也就是所有位置)将当前位置对应到旋转后的位置为temp[j][N - i - 1] = matrix[i][j]
- 按照对应关系推演每一个像素旋转后的位置并记录,遍历结束后将记录的位置拷贝回原数组。
思路二:
- 因为是正方形矩阵,所以旋转一个位置一定同时牵动了其它三个位置
- 根据方法一中的位置对应关系将当前位置带入,推出四个位置的变化关系
- 限定遍历范围,确保每一个位置都只旋转一次并覆盖到所有发生变化的位置
- 如果是偶数边长的矩阵,可以横竖分别对折平分成四个小正方形
- 如果是奇数边长,则排除中心位置(旋转后位置不变),按高比宽长一位(或者相反)的平分成四个小矩形
- 遍历完成后将数组返回
思路三:
从最外圈往内一圈圈旋转
三、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整除即可。