力扣【48-旋转图像】【数组-C语言】

发布于:2024-10-15 ⋅ 阅读:(47) ⋅ 点赞:(0)

题目:力扣-48

给定一个 n × n 的二维矩阵 M 表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

在这里插入图片描述
写代码之前先分析矩阵旋转的本质:
矩阵顺时针旋转90°就是矩阵的第一行变为倒数第一列,第二行变为倒数第二列,第三列变为倒数…(仅看行),相当于平时拿手机时竖着看,现要看电影手机则横着放。再看下对应的数字位置的变化情况,我们把矩阵中的每个元素所在的行列看作在平面坐标系下的坐标。以示例2中矩阵第一个数字(5)为例,数字5会移动到数字11的位置上,11移动到数字16的位置上,15移动到5数字最初的位置,这就是顺时针旋转90°后,一个元素的位置变化(一个数字位置的变化会导致其他数字位置相应的变化,我把这些变化的位置串起来(路径)称为“一轮”),下面列举第一行每个数字一轮后的位置变化路径。

注:总共nxn的矩阵,其中n=4,同时(i,j) 表示:i行,j列,
第一个数字(5)
  5  --> 11  --> 16  --> 15  --> 5(最初位置)
(0,0)-->(0,3)-->(3,3)-->(3,0)-->(0,0)
观察发现:数字的下一个位置的行坐标就是上一个位置的列坐标,即上一个位置(i,j),则下一个位置的坐标(j,x)  x表示未知,目前暂时看不出什么变化
但注意上面提到的:第一行(行坐标就是i)旋转后变为倒数第一列(总共列数为n,列坐标范围0~(n-1)),试着列出列坐标j的表达式:j=(n-1)-i,带入上数字验证没问题,下面两个可以接着验证,这里就不在赘述。

第二个数字(1)
  1  --> 10  --> 12  --> 13  -->  1(最初位置)
(0,1)-->(1,3)-->(3,2)-->(2,0)-->(0,1)
第三个数字(9)
  9  -->  7  --> 14  -->  2  -->  9(最初位置)
(0,2)-->(2,3)-->(3,1)-->(1,0)-->(0,2)
...

最终:我们得出矩阵(用M表示)中数字M[i][j],经过旋转后新的位置为:(j,n-i-1),即 M[j][n-i-1]
注意:看整体:第一行变为倒数第一列(位置关系已给出),原倒数第一列变为最后一行,原最后一行变为第一列,原第一列变为第一行。

方法一:采用辅助数组

思路:用一个和矩阵M大小一致的辅助数组M_new(二维数组),遍历矩阵M,把位置(i,j)上的数字移动到新数组(j,n-i-1)位置上,最后在把新数组拷贝到原来矩阵M里即可(代码略)

方法二:原地移动数字(空间复杂度为O(1))

思路:由前面的分析可知,一个数字一轮后,总共要移动四个方向的数字各一次(上—>右---->下---->左---->上)共4次,而每个数字的新位置和前面分析位置变化的思路一致(代码实现里略微不一样)

void rotate(int** M, int matrixSize, int* matrixColSize) {
    int n = matrixSize;
    int t1, t2;//临时变量
    for (int i = 0; i < matrixSize / 2; i++) {
        for (int j = i; j < n - 1 - i; j++) {
            t1 = M[j][n - i - 1];//保存M[i][j]的下一个位置上的数字
            t2 = 0;
            M[j][n - i - 1] = M[i][j];//数字M[i][j]移动好了
            
            t2 = M[n - i - 1][n - j - 1];//保存数字M[j][n-i-1]的新位置上的数字,注:行:j,列:n-j-1,和前面分析的差不多,只是符号变了,意义没变。
            M[n - i - 1][n - j - 1] = t1;//数字M[j][n-i-1]移动好了
            
            t1 = M[n - j - 1][i];
            M[n - j - 1][i] = t2;
            
            M[i][j] = t1;//一轮的最后一个要移动的数字,移动到最初位置
        }
    }
}

方法三:(用翻转代替旋转)

思路:这里就不多加描述,其数字移动的本质还是和前面分析的思路一致(公式一致)