【每日算法Day 93】不用额外空间,你会旋转一个矩阵吗?

简介: 给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。不占用额外内存空间能否做到?

题目链接


LeetCode 面试题 01.07. 旋转矩阵[1]

题目描述


给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 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]]

题解


旋转


可以发现,每个格子旋转四次之后都会回到原位。所以对于每个格子,我们只需要交换和它相关的一共四个格子的位置就行了。

对于格子 (i, j) ,我们可以推算出它旋转后的三个新位置是 (j, n-1-i), (n-1-i, n-1-j), (n-1-j, i) 。所以只需要一个临时变量保存其中一个位置的值,然后按顺序交换位置就行了。

当然为了避免重复旋转,我们只能枚举四分之一的格子,如果 n 是偶数,如下图所示,我们可以这划分:

image.png

如果 n 是奇数,可以如下图这么划分:

image.png

当然你也可以不规则的划分,如下图这样,只是代码写起来有点费劲:

image.png

翻转


这题还可以不通过模拟旋转来实现旋转。

上面说过了,格子 (i, j) 旋转后的新位置是 (j, n-1-i)

那么我们可以先沿着主对角线翻转矩阵,这样格子 (i, j) 位置就换到了 (j, i)

然后再左右翻转一下矩阵,格子 (j, i) 就换到了 (j, n-1-i) ,正好等价于旋转后的位置!

因为翻转每次只需要交换两个格子的位置,所以不需要任何额外变量。

再提一个交换两个元素的小 trick ,如代码里注释的那样,可以采用异或操作来规避额外变量。

代码


旋转(c++)

classSolution {
public:   
voidrotate(vector<vector<int>>&matrix) {    
intn=matrix.size(); 
for (inti=0; i<n/2; ++i) {  
for (intj=0; j< (n+1)/2; ++j) {   
inttmp=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] =matrix[i][j];  
matrix[i][j] =tmp;  
            }     
        }   
    }
};

翻转(c++)

classSolution {
public:  
voidrotate(vector<vector<int>>&matrix) {  
intn=matrix.size();   
for (inti=0; i<n; ++i) {   
for (intj=i+1; j<n; ++j) { 
matrix[i][j] ^=matrix[j][i];   
matrix[j][i] ^=matrix[i][j];  
matrix[i][j] ^=matrix[j][i]; 
// swap(matrix[i][j], matrix[j][i]);              }   
        }     
for (inti=0; i<n; ++i) {     
for (intj=0; j<n/2; ++j) {  
matrix[i][j] ^=matrix[i][n-1-j];  
matrix[i][n-1-j] ^=matrix[i][j]; 
matrix[i][j] ^=matrix[i][n-1-j];
// swap(matrix[i][j], matrix[i][n-1-j]);              }     
        }   
    }
};

旋转(python)

classSolution: 
defrotate(self, matrix: List[List[int]]) ->None:   
n=len(matrix)       
foriinrange(n//2): 
forjinrange((n+1)//2):   
tmp=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] =matrix[i][j]   
matrix[i][j] =tmp

翻转(python)

classSolution:  
defrotate(self, matrix: List[List[int]]) ->None: 
n=len(matrix)  
foriinrange(n):   
forjinrange(i+1, n):
matrix[i][j], matrix[j][i] =matrix[j][i], matrix[i]
                [j]    
foriinrange(n):   
forjinrange(n//2):        
matrix[i][j], matrix[i][n-1-j] =matrix[i]
                        [n-1-j], matrix[i][j]

关注【算法码上来】,每日算法干货马上就来!

参考资料


[1]

LeetCode 面试题 01.07. 旋转矩阵: https://leetcode-cn.com/problems/rotate-matrix-lcci/

image.png

作者简介:godweiyang知乎同名华东师范大学计算机系硕士在读,方向自然语言处理与深度学习喜欢与人分享技术与知识,期待与你的进一步交流~


相关文章
|
3天前
|
算法 测试技术 C++
【动态规划】【矩阵快速幂】【滚动向量】C++算法552. 学生出勤记录 II
【动态规划】【矩阵快速幂】【滚动向量】C++算法552. 学生出勤记录 II
|
3天前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-48 算法训练 关联矩阵
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-48 算法训练 关联矩阵
38 0
|
3天前
|
机器学习/深度学习 算法 搜索推荐
【解密算法:时间与空间的博弈】(中)
【解密算法:时间与空间的博弈】
|
3天前
|
存储 算法
【解密算法:时间与空间的博弈】(上)
【解密算法:时间与空间的博弈】
|
1天前
|
存储 算法 物联网
R-Tree算法:空间索引的高效解决方案
【5月更文挑战第17天】R-Tree是用于多维空间索引的数据结构,常用于地理信息系统、数据库和计算机图形学。它通过分层矩形区域组织数据,支持快速查询。文章介绍了R-Tree的工作原理、应用场景,如地理信息存储和查询,以及Python的`rtree`库实现示例。此外,还讨论了R-Tree的优势(如空间效率和查询性能)与挑战(如实现复杂和内存消耗),以及优化和变种,如R* Tree和STR。R-Tree在机器学习、实时数据分析等领域有广泛应用,并与其他数据结构(如kd-trees和quad-trees)进行比较。未来趋势将聚焦于优化算法、动态适应性和分布式并行计算。
14 1
|
3天前
|
算法
【免费】面向多微网网络结构设计的大规模二进制矩阵优化算法
【免费】面向多微网网络结构设计的大规模二进制矩阵优化算法
|
3天前
|
算法 数据可视化
圆填充( CIRCLE PACKING)算法圆堆图圆形空间填充算法可视化
圆填充( CIRCLE PACKING)算法圆堆图圆形空间填充算法可视化
|
3天前
|
存储 算法 算法框架/工具
基于HSV色度空间的图像深度信息提取算法FPGA实现,包含testbench和MATLAB辅助验证程序
该文档介绍了在一个FPGA项目中使用HSV色彩模型提取图像深度信息的过程。通过将RGB图像转换为HSV,然后利用明度与深度的非线性映射估计深度。软件版本为Vivado 2019.2和MATLAB 2022a。算法在MATLAB中进行了对比测试,并在FPGA上实现了优化,包括流水线并行处理和查找表技术。提供的Verilog代码段展示了RGB到灰度的转换。实验结果和核心程序的图片未显示。
|
3天前
|
算法 决策智能
深度探讨回溯算法:追寻解空间的奇妙之旅
深度探讨回溯算法:追寻解空间的奇妙之旅
|
3天前
|
算法 测试技术 C++
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串