Leetcode每日一题 —— 1914. 循环轮转矩阵

力扣 LeetCode 1914. 循环轮转矩阵 - 力扣(LeetCode) 1914. 循环轮转矩阵 - 给你一个大小为 m x n 的整数矩阵 grid ,其中 m 和 n 都是 偶数 ;另给你一个整数 k 。 矩阵由若干层组成,如下图所示,每种颜色代表一层: [https://assets....
Leetcode每日一题 —— 1914. 循环轮转矩阵
Leetcode每日一题 —— 1914. 循环轮转矩阵
力扣 LeetCode

1914. 循环轮转矩阵 - 力扣(LeetCode)

1914. 循环轮转矩阵 - 给你一个大小为 m x n 的整数矩阵 grid ,其中 m 和 n 都是 偶数 ;另给你一个整数 k 。 矩阵由若干层组成,如下图所示,每种颜色代表一层: [https://assets.leetcode.com/uploads/2021/06/10/ringofgrid.png] 矩阵的循环轮转是通过分别循环轮转矩阵中的每一层完成的。在对某一层进行一次循环旋转操作时,层中的每一个元素将会取代其 逆时针...


思路

看上去就是模拟题了,可以写个 helper 函数来对每一层进行处理。

咱的思路是对于每一层,计算出其周长 perimeter,然后 k 对周长取模得到实际要轮转的次数 realK

从右上角 (i, j) 开始,找到在周长上距离 (i, j) realK 个格子的位置 (targetI, targetJ),接着螺旋扫描矩阵,同时推进位置 (i, j)(targetI, targetJ),把 (targetI, targetJ) 的值不断赋给 (i, j) 即可。

直接在矩阵上写这套模拟真的挺麻烦的,如果把一层铺平后再处理似乎要好写很多。


代码

咱是直接在矩阵上模拟的,有点屎山了,不过时间复杂度上还算挺快的。

class Solution {
public:
    vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> res(m,vector<int>(n));
        // 通过坐标可以判断目前这个数字在哪一个层级
        // 每一个层级的周长也可以求一下,因为是循环操作,k 可以取模
        // 对于每一层,我们可以从左上角开始,用偏移量定位当前位置在轮转后是哪个元素,然后顺着往下填
        auto rotateLayer=[&](int layer) -> void {
            int i=layer,j=layer; // 这一层的左上角坐标
            int layerM=m-(i<<1),layerN=n-(j<<1);
            // 计算本层周长
            int perimeter=((layerM+layerN)<<1)-4;
            int realK=k%perimeter;
            // 定位,找到周长上距离 (i, j) 有 realK 距离的地方
            int secondDir=0; // 确定后面的方向
            int targetI=i,targetJ=j;
            if(realK<=layerN-1){
                targetJ=j+realK;
            }else if(realK<=(layerN-1)+(layerM-1)){
                targetJ=j+layerN-1;
                targetI=i+realK-(layerN-1);
                secondDir=1;
            }else if(realK<=(layerN-1)+(layerM-1)+(layerN-1)){
                targetI=i+layerM-1;
                targetJ=j+layerN-1-(realK-(layerM-1)-(layerN-1));
                secondDir=2;
            }else{
                targetJ=j;
                targetI=i+layerM-1-(realK-((layerN-1)<<1)-(layerM-1));
                secondDir=3;
            }
            // 现在 (i, j) 位置旋转后的值就是 (targetI, targetJ) 位置的值
            res[i][j]=grid[targetI][targetJ];
            // 接下来就沿着周长顺时针转一圈逐个填上
            int iPos=i,jPos=j;
            int drcts[][2]={
                {0,1},
                {1,0},
                {0,-1},
                {-1,0},
            };
            int firstDir=0;
            perimeter--; // 首个位置已经处理
            while(perimeter>0){
                int newI=iPos+drcts[firstDir][0],newJ=jPos+drcts[firstDir][1];
                if(newI<i||newI>=i+layerM||newJ<j||newJ>=j+layerN){
                    // 越界,换方向
                    firstDir=(firstDir+1)%4;
                    newI=iPos+drcts[firstDir][0];
                    newJ=jPos+drcts[firstDir][1];
                }
                int newTargetI=targetI+drcts[secondDir][0],newTargetJ=targetJ+drcts[secondDir][1];
                if(newTargetI<i||newTargetI>=i+layerM||newTargetJ<j||newTargetJ>=j+layerN){
                    // 越界,换方向
                    secondDir=(secondDir+1)%4;
                    newTargetI=targetI+drcts[secondDir][0];
                    newTargetJ=targetJ+drcts[secondDir][1];
                }
                res[newI][newJ]=grid[newTargetI][newTargetJ];
                iPos=newI;
                jPos=newJ;
                targetI=newTargetI;
                targetJ=newTargetJ;
                perimeter--;
            }
        };
        // 取较短边的一半作为层数
        int numLayers=(min(m,n)>>1);
        for(int i=0;i<numLayers;i++){
            rotateLayer(i);
        }
        return res;
    }
};

2 个帖子 - 2 位参与者

阅读完整话题

来源: LinuxDo 最新话题查看原文