腾讯高频编程考题:旋转图像(中等)

题目描述

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

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

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

解题思路

链接:https://leetcode.cn/problems/rotate-image/solutions/526980/xuan-zhuan-tu-xiang-by-leetcode-solution-vu3m/

题目中要求我们尝试在不使用额外内存空间的情况下进行矩阵的旋转,也就是说,我们需要「原地旋转」这个矩阵。那么我们如何在方法一的基础上完成原地旋转呢?

我们观察方法一中的关键等式:

它阻止了我们进行原地旋转,这是因为如果我们直接将 matrix[row][col] 放到原矩阵中的目标位置 matrix[col][n−row−1]:

原矩阵中的 matrix[col][n−row−1] 就被覆盖了!这并不是我们想要的结果。因此我们可以考虑用一个临时变量 temp 暂存 matrix[col][n−row−1] 的值,这样虽然 matrix[col][n−row−1] 被覆盖了,我们还是可以通过 temp 获取它原来的值:

那么 matrix[col][n−row−1] 经过旋转操作之后会到哪个位置呢?我们还是使用方法一中的关键等式,不过这次,我们需要将

带入关键等式,就可以得到:

同样地,直接赋值会覆盖掉 matrix[n−row−1][n−col−1] 原来的值,因此我们还是需要使用一个临时变量进行存储,不过这次,我们可以直接使用之前的临时变量 temp:

我们再重复一次之前的操作,matrix[n−row−1][n−col−1] 经过旋转操作之后会到哪个位置呢?

带入关键等式,就可以得到:

写进去:

不要灰心,再来一次!matrix[n−col−1][row] 经过旋转操作之后回到哪个位置呢?

带入关键等式,就可以得到:

我们回到了最初的起点 matrix[row][col],也就是说:

这四项处于一个循环中,并且每一项旋转后的位置就是下一项所在的位置!因此我们可以使用一个临时变量 temp 完成这四项的原地交换:

当我们知道了如何原地旋转矩阵之后,还有一个重要的问题在于:我们应该枚举哪些位置 (row,col) 进行上述的原地交换操作呢?由于每一次原地交换四个位置,因此:

当 n 为偶数时,我们需要枚举 n2/4=(n/2)×(n/2) 个位置,可以将该图形分为四块,以 4×4 的矩阵为例:

保证了不重复、不遗漏;

当 n 为奇数时,由于中心的位置经过旋转后位置不变,我们需要枚举个位置,需要换一种划分的方式,以 5×5 的矩阵为例:

同样保证了不重复、不遗漏,矩阵正中央的点无需旋转。

复杂度分析

  • 时间复杂度:O(n^2)。每一层的处理需要遍历 n 个元素,因此总体时间复杂度是 O(n^2)。
  • 空间复杂度:O(1)。只使用了常数级别的额外空间,所有操作都在原矩阵上完成。

代码实现

package org.zyf.javabasic.letcode.hot100.matrix;

import java.util.Arrays;

/**
 * @program: zyfboot-javabasic
 * @description: 旋转图像
 * @author: zhangyanfeng
 * @create: 2024-08-21 23:21
 **/
public class RotateSolution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;

        // 遍历每一层
        for (int i = 0; i < n / 2; ++i) {
            // 每一层的元素交换
            for (int j = 0; j < (n + 1) / 2; ++j) {
                // 交换四个位置上的元素
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - j - 1][i];
                matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
                matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
                matrix[j][n - i - 1] = temp;
            }
        }
    }

    public static void main(String[] args) {
        RotateSolution solution = new RotateSolution();

        // Test Case 1
        int[][] matrix1 = {
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9}
        };
        solution.rotate(matrix1);
        printMatrix(matrix1);
        // Expected output:
        // 7 4 1
        // 8 5 2
        // 9 6 3

        // Test Case 2
        int[][] matrix2 = {
                {5, 1, 9, 11},
                {2, 4, 8, 10},
                {13, 3, 6, 7},
                {15, 14, 12, 16}
        };
        solution.rotate(matrix2);
        printMatrix(matrix2);
        // Expected output:
        // 15 13 2 5
        // 14 3 4 1
        // 12 6 8 9
        // 16 7 10 11

        // Test Case 3
        int[][] matrix3 = {
                {1, 2},
                {3, 4}
        };
        solution.rotate(matrix3);
        printMatrix(matrix3);
        // Expected output:
        // 3 1
        // 4 2
    }

    public static void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
        System.out.println();
    }
}

具体可参考:https://zyfcodes.blog.csdn.net/article/details/141401712

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值