LeetCode——旋转数组(四种解法)

170 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

前言

大家好,我是程序猿小白 GW_gw,很高兴能和大家一起学习进步。

以下内容部分来自于网络,如有侵权,请联系我删除,本文仅用于学习交流,不用作任何商业用途。

摘要

本文主要介绍LeetCode旋转数组的一些解法和思路。

【题目】

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

输入: nums = [1,2,3,4,5,6,7], k = 3

输出: [5,6,7,1,2,3,4]

解释:

向右轮转 1 步: [7,1,2,3,4,5,6]

向右轮转 2 步: [6,7,1,2,3,4,5]

向右轮转 3 步: [5,6,7,1,2,3,4]

题目链接:leetcode-cn.com/leetbook/re…

【解法一】

【思想】

把旋转k个位置进行分解:即每次轮转一个位置,轮转k次(可能会超时)
先对k进行处理,k如果是数组长度的n倍,那么相当于没旋转。
把最后一个保存下来,每个元素依次向后挪,最后把最后一个元素放到第一位。
注意要倒着挪!!!

【代码】

public static void rotate(int[] nums, int k) {
    /*
    解法1:把旋转k个位置进行分解:即每次轮转一个位置,轮转k次
     */
    k = k % nums.length;
    for (int i = 0; i < k; i++) {
        int temp = nums[nums.length - 1];
        for (int j = nums.length - 1; j > 0; j--) {
            nums[j] = nums[j - 1];
        }
        nums[0] = temp;
    }
}

【解法二】

【思想】

利用临时数组
先对k进行处理,k如果是数组长度的n倍,那么相当于没旋转。
用临时数组存放原数组,逐个放回去时把每个元素右移k位。

【代码】

public static void rotate(int[] nums, int k) {
/*
  解法2:利用临时数组
*/
    int length = nums.length;
    //就算这里加了这一句后面还是要进行除余运算,否则仍有可能超出数组长度,并且可以让后面的运算小一些,因为k可能会很大
    k=k%length;
    int[] n = Arrays.copyOf(nums,length);
    for (int i = 0; i < length; i++) {
        //实际上是数学运算,知道思想后,自己动手试一试就知道为什么这样写了。
        nums[(i+k)%length] = n[i];
    }
}

【解法三】

【思想】

数组反转
1)先把整个数组进行反转
2)再把前k个元素进行反转
3)再把后面元素进行反转
上面顺序可以调换,但是原理一样。

【代码】

public static void rotate(int[] nums, int k){
    /*
    解法3:数组反转
     */
    int length = nums.length;
    reverse(nums,0, length-1);
    reverse(nums,0, (k%length)-1);
    reverse(nums,k%length, length-1);
}

public static void reverse(int[] nums,int s,int e){
    while(s<e){
        int temp = nums[s];
        nums[s++] = nums[e];
        nums[e--] = temp;
    }
}

【解法四】

【思想】

循环数组

把数组当作一个环形数组。
先把第k位的元素保存下来,然后第一个元素右移k位。
把第2k位的元素保存下来,把上次保存的第k位元素,继续右移k位,放到2k位置,
剩下元素依次进行,每个元素都要移动,总共进行数组的长度的次数。
如果遇到数组长度为k的整数倍,就会出现原地打转的情况。所以要判断元素是否被访问过,
如果被访问过就把index++,并且更新当前位置,相当于重新从0开始进行操作

图片.png

图片.png

【代码】

public static void rotate(int[] nums, int k){
    /*
    解法4:循环数组
     */
    int length = nums.length;
    k = k%length;
    int index = 0;
    int pos = nums[0];
    boolean[] b = new boolean[length];
    for(int i=0;i<length;i++){
        //一直加k肯定会超过数组长度,所以我们要进行模运算
        index = (index+k)%length;
        if(b[index]){
            index=(index+1)%length;
            pos = nums[index];
            i--;
        }
        else{
            b[index] = true;
            int temp = nums[index];
            nums[index] = pos;
            pos = temp;
        }
    }
}

小结

以上就是关于旋转数组的四种解法,希望能对读者有所帮助,如有不正之处,欢迎留言指正。