LeetCode 1914.循环轮转矩阵:大模拟(数组原地轮转) —— 附O(1)空间版本

【LetMeFly】1914.循环轮转矩阵:大模拟(数组原地轮转) ------ 附O(1)空间版本

力扣题目链接:https://leetcode.cn/problems/cyclically-rotating-a-grid/

给你一个大小为 m x n 的整数矩阵 grid​​​ ,其中 mn 都是 偶数 ;另给你一个整数 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.length
  • n == grid[i].length
  • 2 <= m, n <= 50
  • mn 都是 偶数
  • 1 <= grid[i][j] <=``5000
  • 1 <= k <= 109

解题方法:大模拟

这道题目包含两个部分:

  1. 把矩阵拆成一圈一圈的(共计能拆 min ⁡ { m , n } 2 \frac{\min \{m,n\}}2 2min{m,n}圈)、把一圈的数据写到一个数组中方便进行轮转处理,轮转完成后把数组写回矩阵的这一圈;
  2. 对于一个(上一部分拆分出来的)数组,轮转 k k k次。

对于1.的模拟部分,当我们处理到从外到内第 t h th th圈时,这一圈共有 ( m + n ) × 2 − 4 − 8 × t h (m + n) \times 2 - 4-8\times th (m+n)×2−4−8×th个元素(记为 a l l all all个元素)。创建一个长度为 a l l all all的数组,逆时针遍历这一圈并将数据放入临时一维数组中,待数组完成 k k k-轮转后再次遍历并放回原始矩阵。

对于2.的轮转部分,数组长度为 a l l all all,首先令 k k k对 a l l all all取模,接着把数组向左轮转 k k k次。由于 k < ( m + n ) × 2 − 4 k\lt (m+n)\times 2-4 k<(m+n)×2−4,所以直接模拟 k k k次也行(时间复杂度 O ( a l l × k ) O(all\times k) O(all×k));或者使用一个时间复杂度 O ( a l l ) O(all) O(all)空间复杂度 O ( 1 ) O(1) O(1)的方法更好(懂得原理后也会觉得更加简单):

1 , 2 , 3 , 4 , 5 , 6 , 7 \] \[1, 2, 3, 4, 5, 6, 7\] \[1,2,3,4,5,6,7\]如何向左轮转 3 3 3次变成 \[ 4 , 5 , 6 , 7 , 1 , 2 , 3 \] \[4,5,6,7,1,2,3\] \[4,5,6,7,1,2,3\]呢?三次翻转操作即可。 第一次翻转直接翻转整个数组,第二次翻转前 a l l − k all-k all−k个元素,第三次翻转后 k k k个元素就行了。是的,就这么简单。 1 2 3 4 5 6 7 ------------- ↓ 7 6 5 4 3 2 1 ------- ↓ 4 5 6 7 3 2 1 ----- ↓ 4 5 6 7 1 2 3

  • 时间复杂度 O ( m n ) O(mn) O(mn)
  • 空间复杂度 O ( m + n ) O(m+n) O(m+n),使用了一圈的临时空间

如果你是狠人的话(如ChatGPT),甚至能写个 O ( 1 ) O(1) O(1)空间的原地翻转,记得处理好下标映射就好了。

AC代码

C++
cpp 复制代码
/*
 * @LastEditTime: 2026-05-09 22:15:48
 */
class Solution {
private:
    int n, m, k;
    vector<vector<int>> grid;

    void init(vector<vector<int>>& grid, int k) {
        n = grid.size();
        m = grid[0].size();
        this->grid = move(grid);
        this->k = k;
    }

    void rotate(int th) {
        int m = this->m - 2 * th;
        int n = this->n - 2 * th;
        int all = (m + n) * 2 - 4;
        int k = this->k % all;
        vector<int> round;
        round.reserve(all);

        for (int j = 0; j < m - 1; j++) {
            round.push_back(grid[th][th + j]);
        }
        for (int i = 0; i < n - 1; i++) {
            round.push_back(grid[th + i][th + m - 1]);
        }
        for (int j = m - 1; j > 0; j--) {
            round.push_back(grid[th + n - 1][th + j]);
        }
        for (int i = n - 1; i > 0; i--) {
            round.push_back(grid[th + i][th]);
        }

        reverse(round.begin(), round.end());
        reverse(round.begin(), round.begin() + all - k);
        reverse(round.begin() + all - k, round.end());

        int idx = 0;
        for (int j = 0; j < m - 1; j++) {
            grid[th][th + j] = round[idx++];
        }
        for (int i = 0; i < n - 1; i++) {
            grid[th + i][th + m - 1] = round[idx++];
        }
        for (int j = m - 1; j > 0; j--) {
            grid[th + n - 1][th + j] = round[idx++];
        }
        for (int i = n - 1; i > 0; i--) {
            grid[th + i][th] = round[idx++];
        }
    }
public:
    vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
        init(grid, k);
        
        for (int th = 0; th < min(m, n) / 2; th++) {
            rotate(th);
        }
        return move(this->grid);
    }
};
C++ - GPT写的O(1)空间复杂度版本

相当于把人写的"临时放到数组中"的操作直接给写了个函数映射到原始矩阵中了。

cpp 复制代码
/*
 * @LastEditTime: 2026-05-09 22:42:01
 */
#ifdef _DEBUG
#include "_[1,2]toVector.h"
#endif

class Solution {
private:
    int n, m, k;
    vector<vector<int>> grid;

    void init(vector<vector<int>>& grid, int k) {
        n = grid.size();
        m = grid[0].size();
        this->grid = move(grid);
        this->k = k;
    }

    pair<int, int> locate(int th, int idx) {
        int m = this->m - 2 * th;
        int n = this->n - 2 * th;

        int top = th;
        int bottom = th + n - 1;
        int left = th;
        int right = th + m - 1;

        // 上
        if (idx < m - 1) {
            return {top, left + idx};
        }
        idx -= m - 1;

        // 右
        if (idx < n - 1) {
            return {top + idx, right};
        }
        idx -= n - 1;

        // 下
        if (idx < m - 1) {
            return {bottom, right - idx};
        }
        idx -= m - 1;

        // 左
        return {bottom - idx, left};
    }

    void reverse(int th, int l, int r) {
        while (l < r) {
            auto [x1, y1] = locate(th, l);
            auto [x2, y2] = locate(th, r);
            swap(grid[x1][y1], grid[x2][y2]);
            l++;
            r--;
        }
    }

    void rotate(int th) {
        int m = this->m - 2 * th;
        int n = this->n - 2 * th;

        int all = (m + n) * 2 - 4;
        int k = this->k % all;

        // 左轮转k次
        reverse(th, 0, all - 1);
        reverse(th, 0, all - k - 1);
        reverse(th, all - k, all - 1);
    }

public:
    vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
        init(grid, k);
        
        for (int th = 0; th < min(m, n) / 2; th++) {
            rotate(th);
        }

        return move(this->grid);
    }
};

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源

相关推荐
Hello.Reader1 小时前
算法基础(三)—— 插入排序从整理扑克牌到有序数组
java·算法·排序算法
50万马克的面包1 小时前
C语言:三大基础排序算法模板 冒泡 / 选择 / 插入)
c语言·笔记·算法·排序算法
罗超驿1 小时前
3.快乐数专题学习笔记——双指针法在LeetCode 202题中的应用
java·算法·leetcode·职场和发展
无限进步_1 小时前
【C++】深入底层:自己动手实现一个哈希表
开发语言·数据结构·c++·算法·链表·散列表·visual studio
_深海凉_1 小时前
LeetCode热题100-小于 n 的最大数(字节高频题)
算法·leetcode·职场和发展
小雅痞1 小时前
[Java][Leetcode middle] 36. 有效的数独
java·算法·leetcode
paeamecium1 小时前
【PAT甲级真题】- General Palindromic Number(20)
数据结构·c++·算法·pat考试·pat
北顾笙9802 小时前
day43-数据结构力扣
数据结构·算法·leetcode
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章69-圆弧测量
图像处理·人工智能·opencv·算法·计算机视觉