挑战30天每天一道leetcode题:Day4 #48旋转图像

题目:48旋转图像

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

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

链接:. - 力扣(LeetCode)

分析:

方法一:数学方法(先转置,再左右翻转)

方法二:分治(分四部分再旋转)

我领悟的思想是:

1、先分成4个部分,再用两层循环遍历这四分之一部分。

2、将左右的顶点拿出来,存在一个临时的temp中,再将更新的数字放进入(后面优化直接将第一个顶点存temp中,后面三个顶点直接填进去。)

3、由于有两层循环,所以这四分之一个部分里的所有的元素都会重复顶点的操作,这大概就是分治

ps:搞了三四个小时都搞不懂这一题,靠,太笨了

参考代码:

package com.atguigu.algorithm.arrays;

public class RotateImage {
    //方法一:数学方法(矩阵转置,再翻转每一行(前后对调))
    public void rotate1(int[][] matrix) {
        int n = matrix.length;

        //  1.转置矩阵  双循环,第一层是行,第二层是列(行上具体的点)
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        //  2.翻转每一行
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][n - j - 1];
                matrix[i][n - j - 1] = temp;
            }
        }
    }

    //  方法二:分治思想,分为四个子矩阵分别考虑
    public void rotate2(int[][] matrix) {
        int n = matrix.length;
        //  遍历四分之一矩阵,左上角
        for (int i = 0; i < n / 2 + n % 2; i++) {
            for (int j = 0; j < n / 2; j++) {
                //  对于matrix[i][j],需要找到不同的四分矩阵中对应的另外三个位置和元素
                //定义一个临时数组,保存对应的四个元素
                int[] temp = new int[4];
                int row = i;
                int col = j;
                //行列转换的规律: row + newCol = n-1 , col = newRow
                for (int k = 0; k < 4; k++) {
                    temp[k] = matrix[row][col];
                    int x = row;
                    row = col;
                    col = n - 1 - x;
                }
                //  再次遍历要处理的四个位置,将旋转之后的数据填入
                for (int k = 0; k <4; k++) {
                    //  用上一个值替换当前的位置
                    matrix[row][col] = temp[(k + 3) % 4];
                    int x = row;
                    row = col;
                    col = n - 1 - x;
                }
            }
        }
    }

    //方法三:改进
    public void rotate3(int[][] matrix) {
        int n = matrix.length;

        //遍历四分之一矩阵
        for (int i = 0; i < (n+1)/2; i++) {
            for (int j = 0; j < n / 2; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = 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];    //规律:上一个元素的行+下一个元素的列=n-1
                matrix[j][n - 1 - i] = temp;
            }
        }
    }




    public static void main(String[] args) {
        int[][] image1 = {
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9},
        };

        int[][] image2 = {
                {5, 1, 9, 11},
                {2, 4, 8, 10},
                {13, 3, 6, 7},
                {15, 14, 12, 16}
        };

        RotateImage rotateImage = new RotateImage();
        rotateImage.rotate3(image1);
        rotateImage.printImage(image1);

        rotateImage.rotate3(image2);
        rotateImage.printImage(image2);

    }

    private void printImage(int[][] image) {
        System.out.println("image = " );
        for (int[] line : image) {
            for (int point : line) {
                System.out.print(point+"\t");
            }
            System.out.println();
        }
    }

}

复杂度分析:

方法一的复杂度:
  1. 时间复杂度:O(N^2)
  2. 空间复杂度:O(1)。旋转操作是原地完成的,只耗费常数空间。
方法二、三的复杂度:
  1. 时间复杂度:O(N^2) 是两重循环的复杂度。
  2. 空间复杂度:O(1) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值