LeetCode【#189】Rotate Array(旋转数组)

题目链接:

点击跳转

 

题目:

Given an array, rotate the array to the right by k steps, where k is non-negative.

Example 1:

Input: [1,2,3,4,5,6,7] and k = 3Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]

Example 2:

Input: [-1,-100,3,99] and k = 2Output: [3,99,-1,-100]
Explanation: 
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]

Note:

  • Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
  • Could you do it in-place with O(1) extra space?

题目分析:

给定一个数组,将数组中的元素向右移动 个位置,其中 是非负数。

Note:尝试至少三种方法,空间复杂度O(1)

 

解题思路:

最开始的思路,弄一个新数组,然后根据 (i+k)%len,由原本数组和新数组进行下标匹配,但是这样子的空间复杂度是O(n)。

在所有考虑思路之前,如果 k >nums.length,那么相当于 k 的有效操作是 k%nums.length,这样子可以减少操作。

思路一、那就一次就右移一位,这样子相当于数组的移动,只要空间复杂度O(1)即可,每次先把数组最后一位记下,当数组从第二个开始是前一位的值,然后第一位就用原本记下数组的最后一位。这样子的时间复杂度是 O(kn)。

思路二、把原数组划分为两个部分来看:前 n - k 个元素和 后k个元素,进行分开处理。然后前半部分和后半部分都进行数组反转,然后总的数组进行反转(三次反转)即可。例子:

如果 n = 7 , k = 3,给定数组 [1,2,3,4,5,6,7] ,向右旋转后的结果为 [5,6,7,1,2,3,4]。

第一步:前 n-k 个元素反转----4 3 2 1,后 k 个元素进行反转-----7 6 5

第二步:总的数组进行反转-----5 6 7 1 2 3 4

思路二的难点,如果是C++的话,有自带vector的反转函数,但是Java没有,所以Java需要自己写一个数组反转函数,但这个很简单,就是不断的头尾交换,然后头尾一个++,一个--。

思路三、依旧利用 (i + k) % n 等于新 index 的思路,不过这是每次调换一个元素,后一个元素的调换基于上一个的位置。例子:

如果 n = 6,k = 2,数组[1,2,3,4,5,6].。

1 会到 3的位置---[1,2,1,4,5,6],要记录下3,

然后 3 会到 5的位置---[1,2,1,4,3,6],记录下5,

5 到 1的位置---[5,2,1,4,3,6],如果此时本来记录下1的,但是实际上这个位置是处理过了。

那么我们记录一开始的位置是 0,此时新的位置还是0,再相同处理,则会导致结果出错,因此当新和一开始的位置一样的,说明要从下一个位置再开始。

因此思路三,主要会出错的点就是上面要同时记录最原始位置,和新的位置,当两个位置相等或者不相等的时候,用不同处理。

相等时:说明新和原始位置同时往下移一位,同时记录的值是新位置的值。

不等时:记录当前新位置下的值即可。

时间复杂度是O(n)。

 

AC代码:(Java)

思路一:时间复杂度O(k*n),空间复杂度O(1)

class Solution {
    public void rotate(int[] nums, int k) {
        int len = nums.length;
        k %= len;
        
        for(int i = 0;i < k;i++)
        {
            int temp = nums[len-1];
            for(int j = len-2;j >= 0;--j)
            {
                nums[j+1] = nums[j];
            }
            nums[0] = temp;
        }
        
        return ;
    }
}

思路二:时间复杂度O(n),空间复杂度O(1)

class Solution {
    public static void reverse(int[] arr, int begin, int end) {
        while(begin < end)
        {
            int temp = arr[begin];
            arr[begin++] = arr[end];
            arr[end--] = temp;
        }
	}
    
    public void rotate(int[] nums, int k) {
        int len = nums.length;
        k %= len;
        
        reverse(nums,0,len-k-1);
        reverse(nums,len-k,len-1);
        reverse(nums,0,len-1);
    }
    
}

思路三:时间复杂度O(n),空间复杂度O(1)

class Solution {
    public void rotate(int[] nums, int k) {  
        if (nums.length < 2 || k < 1 || k % nums.length == 0) {
            return;
        }
        
        int currentNum = nums[0];
        int currentIndex = 0;
        int newIndex = 0;
        int i = 0;
        
        while (i++ < nums.length) {
            newIndex = (newIndex + k) % nums.length;
            int temp = nums[newIndex];
            nums[newIndex] = currentNum;
            
            if (currentIndex == newIndex) {
                currentNum = nums[++newIndex];
                ++currentIndex;
            } else {
                currentNum = temp;
            }
        }
        
    }
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值