给你一个大小为 m x n 的整数矩阵 grid ,其中 m 和 n 都是 偶数 ;另给你一个整数 k 。
矩阵由若干层组成,如下图所示,每种颜色代表一层:

矩阵的循环轮转是通过分别循环轮转矩阵中的每一层完成的。在对某一层进行一次循环旋转操作时,层中的每一个元素将会取代其 逆时针方向的相邻元素。轮转示例如下:

返回执行 k 次循环轮转操作后的矩阵。
示例 1:

输入:grid = [[40,10],[30,20]], k = 1
输出:[[10,20],[40,30]]
解释:上图展示了矩阵在执行循环轮转操作时每一步的状态。
示例 2:



输入:grid = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]], k = 2
输出:[[3,4,8,12],[2,11,10,16],[1,7,6,15],[5,9,13,14]]
解释:上图展示了矩阵在执行循环轮转操作时每一步的状态。
提示:
m == grid.lengthn == grid[i].length2 <= m, n <= 50m和n都是 偶数1 <= grid[i][j] <= 50001 <= k <= 10^9
分析:对于一个 m×n 的矩阵 grid,它的层数为 min(m/2,n/2)。可以从外向内枚举矩阵的每一层模拟循环轮转操作。
从左上角起按照逆时针方向遍历每一层的元素,遍历过程分为四个部分,每个部分按顺序遍历每条边除了最后一个元素以外的所有元素。将这些元素的值保存在数组 num 中,并计算元素总数,即数组的长度 len。此时,如果对该层元素进行 len 次循环轮转操作,那么该层元素不会改变。因此,实际的循环轮转操作数量即为 k=k%len。
之后重新按照顺时针遍历行列坐标数组,并在 grid 中更新每个坐标对应的轮转操作后的取值。枚举并更新完所有层后,grid 即为轮转操作后的矩阵。
cpp
class Solution {
public:
vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
vector<vector<int>>ans=grid;
int m=grid.size(),n=grid[0].size(),layer=min(m,n)/2;
for(int l=0;l<layer;++l)
{
int x=0+l,y=0+l,len=(m-l*2)*2+(n-l*2)*2-4,cnt=0;
int left=y,right=n-l,down=m-l,f1,f2;f1=f2=0;
vector<int>num;
while(cnt<len)
{
num.push_back(grid[x][y]);cnt++;
if(y+1<right&&!f1)y++;
else if(x+1<down&&!f2)x++,f1=1;
else if(y-1>=left)y--,f2=1;
else x--;
}
f1=f2=0;
x=0+l,y=0+l;
for(int i=0,j=k%cnt;i<cnt;++i,j=(j+1)%cnt)
{
ans[x][y]=num[j];
if(y+1<right&&!f1)y++;
else if(x+1<down&&!f2)x++,f1=1;
else if(y-1>=left)y--,f2=1;
else x--;
}
}
return ans;
}
};