leetcode_48 旋转图像

发布于:2025-09-02 ⋅ 阅读:(19) ⋅ 点赞:(0)

1. 题意

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

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

2. 题解

2.1 暴力

我们先通过暴力弄明白是怎么转的,顺时针旋转90度;

实际上就是把第一行变成了倒数第一列,第二行变成了倒数第二列。

因此我们可以写出旋转前后的对应关系

m a t r i x [ i ] [ j ] = n e w _ m a t r i x [ j ] [ n − 1 − i ] matrix[i][j] = new\_matrix[j][n-1-i] matrix[i][j]=new_matrix[j][n1i]

用一个新的数组来记录这个新数组,最后再把新数组的值给赋值回来

不就好了吗?

当然这是不符合原地的空间复杂度要求的。

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        
        int n = matrix.size();
        vector<vector<int>> sup(n, vector<int>(n));

        for (int r = 0;r < n; ++r ) {
            for (int c = 0; c < n; ++c) {
                sup[c][n - r - 1] = matrix[r][c];
            }
        }

        matrix = sup;
    }
};
2.2 转置+反转

如果学过矩阵的话,会知道有一种操作叫转置,也就是行列之间互换。

第一行变成了第一列,第二行变成了第二列。

但是这跟我们上面的要求还不符?怎么办呢?

我们反转一下不就好了吗?

反转列是典型的相向双指针不用多说。

而对于转置操作,就是行列互换。

a t [ i ] [ j ] = a [ j ] [ i ] at[i][j] = a[j][i] at[i][j]=a[j][i]

( i , j ) , ( j , i ) (i,j),(j,i) (i,j),(j,i)关于 r = c r=c r=c对称,

我们只需要枚举所有的 i > j i>j i>j或者 i < j i<j i<j的点进行交换就可以了。

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        
        int n = matrix.size();
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                if (i != j) {
                    std::swap(matrix[i][j], matrix[j][i]);
                }
            }
        }

        for ( int i = 0; i < n; ++i) {
            int l = 0,r = n - 1;
            while (l < r) {
                std::swap(matrix[i][l], matrix[i][r]);
                l++;
                r--;
            }
        }
    }
};
2.3 原地旋转

由于有四个方向,每次旋转完后的位置有新的数了。

因此我们需要对于一个位置一直旋转到结束循环为止。

我们假设起始的位置在 ( i , j ) (i,j) (i,j)

上面我们已经知道了它顺时针旋转90度后的位置在 ( j , n − 1 − i ) (j,n-1-i) (j,n1i)

那这个新位置旋转后在哪里呢?

直接代入上面的情况就行了,新的位置在 ( n − 1 − i , n − 1 − j ) (n - 1 -i, n- 1 - j) (n1i,n1j)

继续寻找下一个新位置,下一个新位置在 ( n − 1 − j , i ) (n - 1 - j, i) (n1j,i)

继续寻找下一个新位置,下一个新位置在 ( i , j ) (i , j) (i,j)

这样就构成了一个loop

( i , j ) → ( j , n − 1 − i ) → ( n − 1 − i , n − 1 − j ) → ( n − 1 − j , i ) → ( i , j ) (i,j) \to(j,n-1-i) \to (n-1-i, n-1-j) \\ \to(n-1-j,i) \to (i, j) (i,j)(j,n1i)(n1i,n1j)(n1j,i)(i,j)

对于每个变换的位置,我们只需要按上面的顺序处理就可以了。

接下来要做的是找到所有的需要处理的位置,要不重不漏。

首先是偶数的情况,

很显然只需要处理 0 ≤ i < n / 2 ,   0 ≤ j < n / 2 0\le i < n/2,\ 0 \le j < n/2 0i<n/2, 0j<n/2的情况就可以了。

在这里插入图片描述

其次是奇数的情况,看下面的图吧。

中间的点我们不需要处理。

对于行来说, 0 ≤ i < ⌊ n / 2 ⌋ 0 \le i < \lfloor n/2 \rfloor 0i<n/2

对于列来说, 0 ≤ j ≤ ⌈ n / 2 ⌉ 0 \le j \le \lceil n/2 \rceil 0jn/2

在这里插入图片描述

综合两种情况看

0 ≤ i < ⌊ n / 2 ⌋ 0 ≤ j < ⌊ ( n + 1 ) / 2 ⌋ 0 \le i < \lfloor n/2\rfloor\\ 0 \le j < \lfloor (n+1)/2 \rfloor 0i<n/20j<⌊(n+1)/2

这种方法也就是官方的做法了

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        
        int n = matrix.size();
        

        for (int i = 0; i < n / 2; ++i) {
            for (int j = 0; j < (n + 1) / 2; ++j) {
                int tmp = matrix[i][j];

                matrix[ i         ][ j         ] = matrix[ n - 1 - j ][ i ];
                matrix[ n - 1 - j ][ i         ] = matrix[ n - 1 - i ][ n - 1 - j ];
                matrix[ n - 1 - i ][ n - 1 - j ] = matrix[ j         ][ n - 1 - i ];
                matrix[ j         ][ n - 1 - i ] = tmp;
            }
        }
        
    }
};

另外一种做法是基于层来做旋转,如下图所示.

假设当前层的左端和上端的值为mn

下端和右端的值为mx

对于上端的点 ( m n , i ) (mn, i) (mn,i),它所在的圈层容易求出为

( m n , i ) → ( i , m x ) → ( m x , m x − ( i − m n ) ) → ( m x − ( i − m n ) , m n ) → ( m n , i ) (mn,i) \to(i, mx) \to(mx, mx-(i-mn))\\ \to(mx-(i-mn), mn) \to(mn,i) (mn,i)(i,mx)(mx,mx(imn))(mx(imn),mn)(mn,i)

对于每一层来说, 我们只需要遍历 ( m n , i ) , m n ≤ i < m x (mn,i), mn \le i < mx (mn,i),mni<mx

在一层处理完成后,左右边界往中间收缩,一直处理到 m n ≥ m x mn \ge mx mnmx
在这里插入图片描述

代码

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        
        int n = matrix.size();
        

        int mx = n - 1;
        int mn = 0;

        while ( mn < mx) {
            for (int i = mn; i < mx; ++i) {
                swap(matrix[mn][i], matrix[i][mx]);
                swap(matrix[mn][i], matrix[mx][mx - (i - mn)]);
                swap(matrix[mn][i], matrix[mx - (i - mn)][mn]);
            }
            ++mn;
            --mx;
        }
        
    }
};

参考

leetcode


网站公告

今日签到

点亮在社区的每一天
去签到