美文网首页
0048. 旋转图像

0048. 旋转图像

作者: 蓝笔头 | 来源:发表于2021-08-23 10:02 被阅读0次

    1. 题目地址

    https://leetcode-cn.com/problems/rotate-image/

    2. 题目描述

    给定一个 n × n 的二维矩阵表示一个图像。
    
    将图像顺时针旋转 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]
    ]
    

    3. 题解

    3.1 画图

    Tips:画图举例子分解这三种办法能够帮助我们解决复杂的问题。

    旋转前后对比

    (1)位置 [0,0] 的旋转路径,如下图所示:

    (2)位置 [0,1] 的旋转路径,如下图所示:

    (3)位置 [0,n-2](或者说 [1, 0])的旋转路径,如下图所示:

    (3)位置 [1,1] 的旋转路径,如下图所示:

    通过图例,我们可以知道,一个位置 [i,j] 进行旋转,只会和其他三个位置的数字进行交换。

    3.2 找规律

    3.2.1 旋转规律

    假设某一个在上方的数字下标为 [i, j],需要进行四次旋转,才能把 [i, j] 对应的四个位置的数都放到最终的位置。

    需要转移的四个数为:

    • 上:[i, j]
    • 右:[j, n-1-i]
    • 下:[n-1-i, n-1-j]
    • 左:[n-1-j, i]

    转移路径:

    • 从左到上:[i, j] = [n-1-j, j]
    • 从上到右:[j, n-1-i] = [i,j]
    • 从右到下:[n-1-i, n-1-j] = [j, n-1-i]
    • 从下到左:[n-1-j, i] = [n-1-i, n-1-j]

    代码如下所示:

        /**
        转移路径:
    - 从左到上:`[i, j] = [n-1-j, j]`
    - 从上到右:`[j, n-1-i] = [i,j]`
    - 从右到下:`[n-1-i, n-1-j] = [j, n-1-i]`
    - 从下到左:`[n-1-j, i] = [n-1-i, n-1-j]`
         */
        public void rotate(int[][] matrix, int i, int j) {
            int n = matrix.length;
    
            int top = matrix[i][j];
            int right = matrix[j][n-1-i];
            int bottom = matrix[n-1-i][n-1-j];
            int left = matrix[n-1-j][i];
            
            // 从左到上:[i, j] = [n-1-j, j]
            matrix[i][j] = left;
            // 从上到右:[j, n-1-i] = [i,j]
            matrix[j][n-1-i] = top;
            // 从右到下:[n-1-i, n-1-j] = [j, n-1-i]
            matrix[n-1-i][n-1-j] = right;
            // 从下到左:[n-1-j, i] = [n-1-i, n-1-j]
            matrix[n-1-j][i] = bottom;
        }
    

    3.2.2 n 为偶数

    一个 n * n 的矩阵,如果是 n 是偶数的话,那么可以划分为 4 个 n/2 * n/2
    因为上面的转移函数是从左上方开始的,所以我们只需要转移下图中编号为 1 的子矩阵即可。

    也就是说,使用之前的转移方程下面的编号即可。

    [0,0] [0,1] ... [0,n/2-1]
    [1,0] [1,1] ... [1, n/2-1]
    ...
    [n/2-1,0] [n/2-1,1] ... [n/2-1,n/2-1]
    

    3.2.3 n 为奇数

    • 旋转如下矩阵:
    [0,0] [0,1] ... [0,n/2-1] [0,n/2]
    [1,0] [1,1] ... [1, n/2-1] [1,n/2]
    ...
    [n/2-1,0] [n/2-1,1] ... [n/2-1,n/2-1] [n/2-1,n/2]
    

    [n/2, n/2] 这个点不进行旋转。

    完整代码如下所示:

    class Solution {
        public void rotate(int[][] matrix) {
            int length = (matrix.length + 1) / 2;
            int width = matrix.length / 2;
            for (int i = 0; i < length; ++ i) {
                for (int j = 0; j < width; ++ j) {
                    rotate(matrix, i, j);
                }
            }
        }
    
        /**
        转移路径:
    - 从左到上:`[i, j] = [n-1-j, j]`
    - 从上到右:`[j, n-1-i] = [i,j]`
    - 从右到下:`[n-1-i, n-1-j] = [j, n-1-i]`
    - 从下到左:`[n-1-j, i] = [n-1-i, n-1-j]`
         */
        public void rotate(int[][] matrix, int i, int j) {
            int n = matrix.length;
    
            int top = matrix[i][j];
            int right = matrix[j][n-1-i];
            int bottom = matrix[n-1-i][n-1-j];
            int left = matrix[n-1-j][i];
            
            // 从左到上:[i, j] = [n-1-j, j]
            matrix[i][j] = left;
            // 从上到右:[j, n-1-i] = [i,j]
            matrix[j][n-1-i] = top;
            // 从右到下:[n-1-i, n-1-j] = [j, n-1-i]
            matrix[n-1-i][n-1-j] = right;
            // 从下到左:[n-1-j, i] = [n-1-i, n-1-j]
            matrix[n-1-j][i] = bottom;
        }
    }
    
    • 或者旋转如下矩阵:
    [0,0] [0,1] ... [0,n/2-1]
    [1,0] [1,1] ... [1, n/2-1]
    ...
    [n/2-1,0] [n/2-1,1] ... [n/2-1,n/2-1]
    [n/2,0] [n/2,1] ... [n/2,n/2-1]
    

    [n/2, n/2] 这个点不进行旋转。

    完整代码如下所示:

    class Solution {
        public void rotate(int[][] matrix) {
            int length = (matrix.length) / 2;
            int width = (matrix.length + 1) / 2;
            for (int i = 0; i < length; ++ i) {
                for (int j = 0; j < width; ++ j) {
                    rotate(matrix, i, j);
                }
            }
        }
    
        /**
        转移路径:
    - 从左到上:`[i, j] = [n-1-j, j]`
    - 从上到右:`[j, n-1-i] = [i,j]`
    - 从右到下:`[n-1-i, n-1-j] = [j, n-1-i]`
    - 从下到左:`[n-1-j, i] = [n-1-i, n-1-j]`
         */
        public void rotate(int[][] matrix, int i, int j) {
            int n = matrix.length;
    
            int top = matrix[i][j];
            int right = matrix[j][n-1-i];
            int bottom = matrix[n-1-i][n-1-j];
            int left = matrix[n-1-j][i];
            
            // 从左到上:[i, j] = [n-1-j, j]
            matrix[i][j] = left;
            // 从上到右:[j, n-1-i] = [i,j]
            matrix[j][n-1-i] = top;
            // 从右到下:[n-1-i, n-1-j] = [j, n-1-i]
            matrix[n-1-i][n-1-j] = right;
            // 从下到左:[n-1-j, i] = [n-1-i, n-1-j]
            matrix[n-1-j][i] = bottom;
        }
    }
    

    时间复杂度:O(n^2),n 为矩阵的大小。
    空间复杂度:O(1)

    相关文章

      网友评论

          本文标题:0048. 旋转图像

          本文链接:https://www.haomeiwen.com/subject/lodfiltx.html