数组和矩阵问题:将正方形矩阵顺时针转动90度

本文介绍了一种在额外空间复杂度为O(1)的情况下,将N*N矩阵顺时针旋转90度的算法。通过分圈处理,每次旋转子矩阵的外层,直至整个矩阵旋转完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

  给定一个 N*N 的矩阵 matrix, 把这个矩阵调整成顺时针转动90度后形式。

  例如:

  1    2    3    4

  5    6    7    8

  9    10  11  12

  13  14  15  16

  顺时针转动90度后为:

  13  9    5    1

  14  10  6    2

  15  11  7    3 

  16  12  8    4

要求

  额外空间复杂度为 O(1)

难度

  一星

解答

  这里仍然使用分圈处理的方式,在矩阵中用左上角的坐标(tR, tC)和右下角的坐标(dR, dC) 就可以表示一个子矩阵。比如,题目中的矩阵,当(tR, tC)=(0,0), (dR,dC)=(3,3) 时,表示的子矩阵就是整个矩阵,那么这个子矩阵最外层的部分如下:

  1   2   3  4

  5            8

  9                 12

  13     14     15    16

  在这个外圈中, 1,4,16,13 为一组,然后让1占据4的位置,4占据16的位置,16占据13的位置,13占据1的位置,一组就调整完了。然后,2,8,15,9 为一组,继续占据调整的过程,最后 3,12,14,5 为一组,继续占据调整的过程。然后(tR, tC)=(0,0)、(dR,dC)=(3,3) 的子矩阵外层就调整完毕了。接下来令tR和tC加1,dR和dC减1,即(tR,tC)=(1,1), (dR, dC)=(2,2), 此时表示的子矩阵如下:

  6    7

  10  11

  这个外层只有一组,就是6,7,11,10,占据调整之后即可。所以,如果子矩阵的大小是M*M,一共就有 M-1 组, 分别进行占据调整即可。

  具体过程请参看如下代码的 rotate 方法。

 1 public class Main {
 2     
 3     public static void main(String[] args) {
 4         int[][] matrix = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
 5         System.out.println("原矩阵:");
 6         for(int i = 0; i < matrix.length; i++){
 7             for(int j = 0; j < matrix[i].length; j++){
 8                 System.out.print(matrix[i][j] + " ");
 9             }
10             System.out.println();
11         }
12         
13         new Main().rotate(matrix);
14         System.out.println("\n顺时针旋转90度后:");
15         for(int i = 0; i < matrix.length; i++){
16             for(int j = 0; j < matrix[i].length; j++){
17                 System.out.print(matrix[i][j] + " ");
18             }
19             System.out.println();
20         }
21     }
22     
23     //顺时针旋转90度
24     public void rotate(int[][] matrix){
25         int tR = 0;
26         int tC = 0;
27         int dR = matrix.length - 1;
28         int dC = matrix[0].length - 1;
29         while(tR <= dR && tC <= dC){
30             rotateEdge(matrix, tR++, tC++, dR--, dC--);
31         }
32     }
33     
34     //旋转子矩阵外层
35     public void rotateEdge(int[][] m, int tR, int tC, int dR, int dC){
36         //确定旋转次数
37         int times = dR - tR;
38         for(int i = 0; i < times; i++){
39             //要交换的四个位置按顺时针方向分别为:m[tR][tC+i]、m[tR+i][dC]、m[dR][dC-i]、m[dR-i][tC]
40             int tmp = m[tR][tC+i];
41             m[tR][tC+i] = m[dR-i][tC];
42             m[dR-i][tC] = m[dR][dC-i];
43             m[dR][dC-i] = m[tR+i][dC];
44             m[tR+i][dC] = tmp;
45         }
46     }
47     
48 }

 

转载于:https://www.cnblogs.com/zlxyt/p/10514666.html

牛客网作为国内知名的编程学习平台,提供了大量与二维数组矩阵相关的练习题,这些题目广泛涵盖了基础操作、算法设计以及复杂逻辑处理等方面,适合不同水平的学习者进行练习。以下是几个与二维数组矩阵相关的典型练习题单: ### 1. 二维数组中的查找 题目要求在一个二维数组中查找特定的整数。该二维数组具有如下特性:每一行都按照从左到右递增的顺序排序,每一列也按照从上到下的顺序排序。这类题目需要利用数组的有序性来设计高效的查找算法。例如,可以从数组的右上角或左下角开始查找,根据当前元素与目标值的大小关系决定下一步的方向,从而在 $O(n)$ 的时间复杂内完成查找[^4]。 ### 2. 矩阵顺时针打印 题目要求将一个矩阵按照顺时针螺旋的顺序输出。例如对于一个 $4 \times 4$ 的矩阵输出顺序应该是从左到右第一行,接着从上到下最后一列,然后从右到左最后一行,最后从下到上第一列,依次类推直到所有元素都被访问。这类题目考察的是对数组边界的控制能力,通常采用模拟的方法,通过维护当前的边界(上、下、左、右)来逐步缩小访问范围[^1]。 ### 3. 矩阵乘法 题目要求实现两个大矩阵的乘法运算,并需要考虑内存存储方式对计算速的影响。在实际计算中,为了提高缓存命中率,通常建议将矩阵按行存储用于乘法运算,因为矩阵乘法的核心操作是行与列的点积,而按行存储可以保证在访问行向量时数据在内存中是连续的,从而提升性能[^2]。 ### 4. 二维数组打乱顺序 题目要求对一个二维数组进行打乱顺序的操作。这类题目通常需要利用随机数生成器,通过 Fisher-Yates 洗牌算法的思想,对数组中的元素进行随机交换。需要注意的是,为了保证打乱的均匀性,每次交换的索引应该是从当前索引到数组末尾之间随机选取的[^3]。 ### 5. 矩阵置零 题目要求将一个矩阵中所有值为零的元素所在的行列全部置零。这类问题通常需要利用额外的空间来记录需要置零的行列,或者通过优化空间复杂的方式(例如利用矩阵的第一行第一列作为标记数组)来完成操作。 ### 6. 矩阵旋转 题目要求将一个矩阵顺时针旋转 90 。这类问题可以通过分层旋转的方式解决,即逐层处理矩阵的外圈,将元素逐个移动到正确的位置。另一种方法是先对矩阵进行水平翻转,然后再进行主对角线翻转,从而达到顺时针旋转的效果。 ### 7. 矩阵中的路径 题目要求判断在一个字符矩阵中是否存在一条连续的路径,使得路径上的字符组成一个特定的字符串。这类问题通常使用深优先搜索(DFS)或回溯法来解决,通过递归的方式尝试每一条可能的路径,并在无法继续时回溯到上一步。 ### 8. 矩阵中的最大正方形 题目要求在一个0 1 组成矩阵中找到最大的只包含 1正方形。这类问题可以通过动态规划的方法解决,其中状态定义为以当前点为右下角的最大正方形的边长,状态转移方程依赖于其上方、左侧左上方的状态值。 ### 示例代码:顺时针打印矩阵 以下是一个实现顺时针打印矩阵的示例代码: ```python def spiral_order(matrix): if not matrix: return [] result = [] top, bottom = 0, len(matrix) - 1 left, right = 0, len(matrix[0]) - 1 while top <= bottom and left <= right: # 从左到右 for i in range(left, right + 1): result.append(matrix[top][i]) top += 1 # 从上到下 for i in range(top, bottom + 1): result.append(matrix[i][right]) right -= 1 # 从右到左 if top <= bottom: for i in range(right, left - 1, -1): result.append(matrix[bottom][i]) bottom -= 1 # 从下到上 if left <= right: for i in range(bottom, top - 1, -1): result.append(matrix[i][left]) left += 1 return result ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值