本次周赛第二题是一道矩阵旋转题目,本篇重点讨论一下旋转题目如何处理。
给你一个大小为 m x n 的整数矩阵 grid ,其中 m 和 n 都是 偶数 ;另给你一个整数 k 。返回执行 k 次循环轮转操作后的矩阵。
本题的旋转不是旋转角度,而是旋转步数,我们可以先将矩阵分为多层,每一层单独旋转。
矩阵的层数是
这道题比较有意思的地方是可以将每一层的数据放到一个数组中,然后走几步就是增加步数取余操作。可以理解为通过取余做成循环数组。
class Solution {
public:
vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
int m = grid.size();
int n = grid[0].size();
int nlayer = min(m / 2, n / 2); // 层数
// 从左上角起逆时针枚举每一层
for (int layer = 0; layer < nlayer; ++layer){
vector<int> r, c, val; // 每个元素的行下标,列下标与数值
for (int i = layer; i < m - layer - 1; ++i){ // 左
r.push_back(i);
c.push_back(layer);
val.push_back(grid[i][layer]);
}
for (int j = layer; j < n - layer - 1; ++j){ // 下
r.push_back(m - layer - 1);
c.push_back(j);
val.push_back(grid[m-layer-1][j]);
}
for (int i = m - layer - 1; i > layer; --i){ // 右
r.push_back(i);
c.push_back(n - layer - 1);
val.push_back(grid[i][n-layer-1]);
}
for (int j = n - layer - 1; j > layer; --j){ // 上
r.push_back(layer);
c.push_back(j);
val.push_back(grid[layer][j]);
}
int total = val.size(); // 每一层的元素总数
int kk = k % total; // 等效轮转次数
// 找到每个下标对应的轮转后的取值
for (int i = 0; i < total; ++i){
int idx = (i + total - kk) % total; // 轮转后取值对应的下标
grid[r[i]][c[i]] = val[idx];
}
}
return grid;
}
};
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
这一题是旋转角度,矩阵是正方形。这个题目要求原地旋转矩阵,也就是不使用额外的矩阵。这里先讲下如何使用额外的矩阵做法。
对于矩阵:
第一行旋转后是:
第二行旋转后是:
对于矩阵中的第三行和第四行同理。这样我们可以得到规律:
对于矩阵中第 i 行的第 j 个元素,在旋转后,它出现在倒数第 i 列的第 j 个位置
写成代码就是:
变成了
行变成了列,列变成了倒数的行。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
auto matrix_new = matrix;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix_new[j][n - i - 1] = matrix[i][j];
}
}
matrix = matrix_new;
}
};
原地旋转会复杂些,有2种思路,这里讲下简单的。
矩阵通过水平翻转和对角线翻转后刚好是旋转90的矩阵,如下图:
水平翻转
对角线翻转
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// 水平翻转
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
swap(matrix[i][j], matrix[n - i - 1][j]);
}
}
// 主对角线翻转
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};
复杂的思路是使用一个临时变量存储一个位置,然后每次操作4个位置的变换,最终达到变换整个矩阵的目的,由于过程较为复杂,记忆难度较大,这里不细说了。
给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。
实例:
这道题是一道简单题,但是和48题一样的解法,48题是因为需要原地操作矩阵才是中等题。
class Solution {
public:
bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
int n = mat.size();
int m = mat[0].size();
for (int i = 0; i < 4; ++i) {
vector<vector<int>> tmp(n, vector<int>(m));
for (int j = 0; j < n; ++j) {
for (int k = 0; k < m; ++k) {
tmp[k][m - 1- j] = mat[j][k];
}
}
if (tmp == target) return true;
mat = tmp;
}
return false;
}
};