48. 旋转图像

题目

贪心

题目很有意思,不能使用新的矩阵来存储结果,只能在原数组上进行操作,考虑到矩阵的维度,那么必然有某种规律。

首先假设只能用一个 temp 来存储矩阵中的某个元素,那么一共需要连续进行四次赋值操作才能实现一个循环,以四维矩阵为例,一次循环操作流程如下:

temp = matrix[0][0];
matrix[0][0] = matrix[3][0];
matrix[3][0] = matrix[3][3];
matrix[3][3] = matrix[0][3];
matrix[0][3] = temp;

既然完成了一个循环,那么我们来探索一下其中的奥妙:

    1. 将元素的起始点记录下来:sx = 0; sy = 0;
    1. 用两个变量记录目标元素的位置:tx = 3; ty = 0;
    1. 下一个元素的位置即为:x = sx + tx; y = sy + ty;
    1. 考虑下一步的位置,首先对起始点位置更新:sx = sx + tx; sy = sy + ty;
    1. 根据猜测的规律,对移动变量进行更新:swap(tx, ty); tx = -tx;
    1. 下一个元素的位置即为:x = sx + tx; sy = sy + ty;

通过验证,发现第一个元素的旋转确实满足上述规律,考虑到每四次操作达成一个循环,因此四次操作后就回到了最开始的点:sx = 0; sy = 0;

那么开始考虑其他位置:

    1. 使起始点右移一位:sy = sy + 1;
    1. 跑一边上面的旋转流程,发现满足规律;
    1. 起始点继续右移,直到:sy = n - 1; 结束;

我们可以发现,上一步结束后,成功对矩阵的最外圈完成旋转,该步骤可以称为一次“旋转”。

既然能完成最外圈,那么也能对内圈进行同样的操作,只不过此时的起始点变为了:sx = 1; sy = 1; ,矩阵的维度也变成了:n = n - 2;

根据规律可以发现,只要完成 n / 2 次“旋转”,就可以完成整个矩阵的旋转操作。

class Solution {
public:
    void rotates(vector<vector<int>>& matrix, int sx, int sy, int sn) { // 一次“旋转”操作
        int tx = sn - 1, ty = 0;
        for(int i = 1; i < sn; ++i) {
            int temp = matrix[sx][sy];
            matrix[sx][sy] = matrix[sx + tx][sy + ty];
            sx = sx + tx; sy = sy + ty;
            swap(tx, ty); tx = -tx;
            matrix[sx][sy] = matrix[sx + tx][sy + ty];
            sx = sx + tx; sy = sy + ty;
            swap(tx, ty); tx = -tx;
            matrix[sx][sy] = matrix[sx + tx][sy + ty];
            sx = sx + tx; sy = sy + ty;
            swap(tx, ty); tx = -tx;
            matrix[sx][sy] = temp;
            sx = sx + tx; sy = sy + ty;
            swap(tx, ty); tx = -tx;
            sy++; tx--; ty--;
        }
    }

    void rotate(vector<vector<int>>& matrix) {
        int flag = matrix.size(); // 记录矩阵维度变化
        for(int i = 0; i < matrix.size() / 2; ++i) {
            rotates(matrix, i, i, flag);
            flag-=2;
        }
    }
};

二次对称法

观察可以发现,旋转操作实际上就是对称操作的集合:

  • 按 y 轴对称;
  • 按副对角线对称。
class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        int mid = n / 2;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < mid; ++j)
                swap(matrix[i][j], matrix[i][n - j - 1]);
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n - i - 1; ++j) 
                swap(matrix[i][j], matrix[n - j - 1][n - i - 1]);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BeZer0

打赏一杯奶茶支持一下作者吧~~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值