【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),完全满足了原地旋转的要求。

参考灵神

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

相关推荐
cyforkk34 分钟前
ArrayList vs LinkedList:底层原理与实战选择指南
java
孟婆来包棒棒糖~2 小时前
泛型与反射
java·反射·javase·泛型
A尘埃2 小时前
Spring Event 企业级应用
java·spring·event
超级皮皮3 小时前
力扣热题之stack
算法·leetcode·职场和发展
weixin_470740363 小时前
某算法的python执行汇编
汇编·python·算法
是乐谷4 小时前
燧原科技招大模型训练算法工程师
科技·算法
YuTaoShao4 小时前
【LeetCode 热题 100】139. 单词拆分——(解法一)记忆化搜索
java·算法·leetcode·职场和发展
圣保罗的大教堂5 小时前
leetcode 1277. 统计全为 1 的正方形子矩阵 中等
leetcode
Best_Liu~5 小时前
策略模式 vs 适配器模式
java·spring boot·适配器模式·策略模式
direction__5 小时前
Java Main无法初始化主类的原因与解决方法(VsCode工具)
java·vscode