1914. 循环轮转矩阵

矩阵的循环轮转(按层逆时针旋转)详解及代码实现


题目描述

给定一个大小为 m×nm \times nm×n 的整数矩阵 grid,其中 m 和 n 都是偶数;同时给定一个整数 kkk

矩阵由若干层组成,每层是矩阵中从外围到内圈的同心环。题目要求对矩阵中的每一层分别进行 逆时针循环轮转 操作,共执行 kkk 次。具体来说,一次循环轮转操作是将该层中的每个元素向逆时针方向移动一格。

例如,最外层的元素按逆时针方向整体移动一次位置;同理,内层元素也按逆时针移动一次。

需要返回执行完所有层的 kkk 次循环轮转后的矩阵。


示例说明

示例 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]]

解释:
矩阵有两层,分别逆时针旋转两次,最终结果如上。


题目分析

这个题目核心是理解矩阵“层”的概念和如何对每层进行逆时针旋转。

矩阵的“层”是由矩阵外围向内圈一层一层定义的。例如,对于 4×44 \times 44×4 矩阵,

  • 第一层是最外圈边界的元素;
  • 第二层是内圈(去掉最外圈之后剩余部分)的外围元素。

每层的元素数量是有限的,可以看成一个一维环形数组,题目要求对这个环形数组逆时针旋转 kkk 次。


解题思路

  1. 提取每层元素到一维数组
    遍历每层,按逆时针顺序依次收集该层的所有元素,存储到一个列表中。
  2. 计算实际旋转步数
    因为旋转 kkk 次可能远大于层长度,实际旋转只需考虑 kmod层长度k \mod \text{层长度},避免无效旋转。
  3. 旋转数组
    将提取出来的数组进行左移(逆时针旋转)操作。
  4. 写回矩阵
    按照之前提取的顺序,把旋转后的数组元素写回矩阵对应层的位置。
  5. 重复以上操作,对所有层进行旋转

代码实现(Python)

from typing import List

class Solution:
    def rotateGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        m, n = len(grid), len(grid[0])
        layers = min(m, n) // 2  # 层数
        res = [row[:] for row in grid]  # 复制矩阵,避免原地修改影响读取

        for layer in range(layers):
            elements = []

            # 提取当前层元素,按逆时针顺序存入elements

            # 上边 (从左到右)
            for j in range(layer, n - layer):
                elements.append(grid[layer][j])
            # 右边 (从上到下)
            for i in range(layer + 1, m - layer - 1):
                elements.append(grid[i][n - layer - 1])
            # 下边 (从右到左)
            for j in range(n - layer - 1, layer - 1, -1):
                elements.append(grid[m - layer - 1][j])
            # 左边 (从下到上)
            for i in range(m - layer - 2, layer, -1):
                elements.append(grid[i][layer])

            length = len(elements)
            rotate_k = k % length  # 计算有效旋转步数

            # 旋转元素数组,逆时针旋转相当于左移 rotate_k 个位置
            rotated = elements[rotate_k:] + elements[:rotate_k]

            # 将旋转后的元素写回矩阵
            idx = 0

            # 上边
            for j in range(layer, n - layer):
                res[layer][j] = rotated[idx]
                idx += 1
            # 右边
            for i in range(layer + 1, m - layer - 1):
                res[i][n - layer - 1] = rotated[idx]
                idx += 1
            # 下边
            for j in range(n - layer - 1, layer - 1, -1):
                res[m - layer - 1][j] = rotated[idx]
                idx += 1
            # 左边
            for i in range(m - layer - 2, layer, -1):
                res[i][layer] = rotated[idx]
                idx += 1

        return res

复杂度分析

  • 时间复杂度:
    每个元素被访问并移动一次,整体是O(m×n)O(m \times n )O(m×n)
  • 空间复杂度:
    额外空间主要是用于存储每层元素的临时数组,最坏情况下约为矩阵元素数量的一半,空间复杂度为 O(m×n)O(m \times n)O(m×n)

代码解析

  • layers = min(m, n) // 2:计算有多少层,取矩阵较小边长的一半(偶数保证层数正确)。
  • 使用双重循环,提取每层元素。
  • 对提取的一维数组进行旋转,避免旋转次数过大导致性能问题。
  • 旋转后的数组按原路径写回结果矩阵。

方案对比

  1. 直接模拟旋转
    对每层进行 kkk 次单步旋转,效率极低,尤其是 kkk 大时不可行。
  2. 数组旋转优化
    利用取模和数组切片实现旋转,效率高且易实现。
  3. 空间优化
    也可以尝试在原矩阵上就地旋转,但实现复杂度增加,不易维护。

总结

本题通过将二维矩阵按层分解为多个一维数组,再对数组进行旋转,巧妙简化了矩阵旋转的复杂度。代码结构清晰,易读易维护,且能应对较大 k 的情况。

掌握此类“矩阵层遍历 + 一维旋转”技巧,对于解决类似环形数组操作及矩阵操作类问题非常有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值