【LeetCode 热题 100】48. 旋转图像——转置+水平翻转

Problem: 48. 旋转图像

题目:给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

文章目录

整体思路

这段代码旨在解决一个经典的矩阵问题:旋转图像 (Rotate Image) 。问题要求将一个 N x N 的二维矩阵顺时针旋转 90 度 ,并且要求是原地完成,即不使用额外的矩阵空间。

该算法采用了一种非常经典且优雅的 "两步变换法" 来实现原地旋转。它将复杂的旋转操作分解为两个更简单、更直观的线性代数变换:转置水平翻转

  1. 第一步:沿主对角线转置矩阵

    • 什么是转置 :矩阵的转置操作就是将其行和列互换。元素 matrix[i][j] 会和 matrix[j][i] 交换位置。
    • 实现方式 :代码通过一个嵌套循环来实现。外层循环 for (int i = 0; i < m; i++) 遍历每一行,内层循环 for (int j = 0; j < i; j++) 只遍历主对角线左下方的元素。
    • 为什么 j < i :这个条件是关键,它确保了每个位于对角线一侧的元素 (i, j) 只与其对应的 (j, i) 交换一次。如果 j 遍历到 m-1,那么每个元素会被交换两次,最终导致矩阵变回原样。
    • 效果 :完成这一步后,原始矩阵 [[1,2,3],[4,5,6],[7,8,9]] 会变成 [[1,4,7],[2,5,8],[3,6,9]]
  2. 第二步:水平翻转矩阵的每一行

    • 什么是水平翻转:对矩阵的每一行进行独立的反转操作。
    • 实现方式 :代码通过一个外层 for-each 循环遍历矩阵的每一行 row。对于每一行,再通过一个内层循环 for (int i = 0; i < row.length / 2; i++) 来实现该行的原地反转。这个内层循环使用经典的双指针思想(一个从头开始,一个从尾开始)来交换元素。
    • 效果 :对上一步转置后的矩阵 [[1,4,7],[2,5,8],[3,6,9]] 的每一行进行翻转,会得到:
      • [1,4,7] -> [7,4,1]
      • [2,5,8] -> [8,5,2]
      • [3,6,9] -> [9,6,3]
    • 最终的矩阵就是 [[7,4,1],[8,5,2],[9,6,3]],这正是原始矩阵顺时针旋转 90 度的结果。

通过将旋转分解为"转置 + 翻转"这两个步骤,算法巧妙地实现了原地旋转,逻辑清晰且易于理解。

完整代码

java 复制代码
class Solution {
    /**
     * 将一个 N x N 的二维矩阵原地顺时针旋转 90 度。
     * @param matrix 要旋转的 N x N 矩阵
     */
    public void rotate(int[][] matrix) {
        // 获取矩阵的维度(N x N,所以 m 即为 N)
        int m = matrix.length;
        
        // 步骤 1: 沿主对角线转置矩阵
        // 即 matrix[i][j] 与 matrix[j][i] 交换
        for (int i = 0; i < m; i++) {
            // 内层循环 j < i 是关键,确保每个元素只交换一次
            for (int j = 0; j < i; j++) {
                // 执行交换
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        
        // 步骤 2: 水平翻转矩阵的每一行
        // 遍历矩阵的每一行
        for (int[] row : matrix) {
            // 使用双指针法原地反转当前行
            // i 从行首开始,m - 1 - i 从行尾开始
            for (int i = 0; i < row.length / 2; i++) {
                // 执行交换
                int temp = row[i];
                row[i] = row[m - 1 - i];
                row[m - 1 - i] = temp;
            }
        }
    }
}

时空复杂度

时间复杂度:O(N^2)

  1. 转置操作
    • 第一个双层 for 循环的迭代次数是 1 + 2 + ... + (N-1),即 N * (N-1) / 2
    • 因此,这部分的时间复杂度是 O(N^2)
  2. 翻转操作
    • 第二个双层 for 循环,外层循环执行 N 次(遍历每一行)。
    • 内层循环对每一行执行 N/2 次交换操作。
    • 总的操作次数约为 N * (N/2)
    • 因此,这部分的时间复杂度也是 O(N^2)

综合分析

算法的总时间复杂度是 O(N^2) + O(N^2) = O(N^2)。这是不可避免的,因为我们至少需要访问矩阵中的每一个元素一次。

空间复杂度:O(1)

  1. 主要存储开销 :该算法直接在输入的 matrix 数组上进行修改,没有创建任何新的、与输入规模 N 成比例的数据结构。
  2. 辅助变量 :只使用了 m, i, j, temprow 等几个常数数量的变量。

综合分析

算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1),完全满足了原地旋转的要求。

参考灵神

建议看一下灵神题解太强了

相关推荐
chao_7892 分钟前
回溯题解——子集【LeetCode】二进制枚举法
开发语言·数据结构·python·算法·leetcode
张小洛6 分钟前
Spring AOP 设计解密:代理对象生成、拦截器链调度与注解适配全流程源码解析
java·后端·spring·spring aop·aop
十盒半价17 分钟前
从递归到动态规划:手把手教你玩转算法三剑客
javascript·算法·trae
GEEK零零七23 分钟前
Leetcode 1070. 产品销售分析 III
sql·算法·leetcode
凌肖战31 分钟前
力扣网编程274题:H指数之普通解法(中等)
算法·leetcode
秋说32 分钟前
【PTA数据结构 | C语言版】将数组中元素反转存放
c语言·数据结构·算法
WebInfra32 分钟前
如何在程序中嵌入有大量字符串的 HashMap
算法·设计模式·架构
Wyc7240941 分钟前
SpringBoot
java·spring boot·spring
Bella_chene43 分钟前
IDEA中无法使用JSP内置对象
java·servlet·intellij-idea·jsp
森焱森1 小时前
APM与ChibiOS系统
c语言·单片机·算法·架构·无人机