Rotate Array

Leetcode中的array的rotate问题

  Leetcode当中有一系列的题目是关于array的,而关于array的问题中又有一些题目是关于array的“rotate”的操作的。准备写一个关于rotate的专题,将关于rotate的问题整理一下。
  闲言少叙,我们直接来看第一题。
  https://leetcode.com/problems/rotate-array/

原题

Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
Hint:
Could you do it in-place with O(1) extra space?
翻译:将长度为n的数组向右旋转k步,比如n=7,k=3,那么数组 [1,2,3,4,5,6,7] 被旋转成[5,6,7,1,2,3,4]。
提示:
你能在O(1)的额外空间中解决这个问题吗。

问题分析

  看到这个问题的基本想法就是每次rotate一步,然后将rotate进行k次就OK了,O(1)也没有什么问题,但是很显然时间复杂度达到O(kn),效率太低啦。其实接下来想的问题就是是否可以仅仅使用swap操作,将元素和他应该到的位置进行swap。
  [1,2,3,4,5,6,7] 被旋转成[5,6,7,1,2,3,4],我将1放到4的位置,4放到7的位置,7放到3的位置,3放到6的位置,6放到2的位置,2放到5的位置,最后5放到1的位置,每次我只要计算出这个被替换掉的元素下一次应该到的位置就行了!看似很完美,额外空间复杂度O(1)。
  实现了一下发现一个问题,只有k%n和n互质的时候,这个方法才有效!
  比如数组为[1,2,3,4],k=2。第一次1换到3,然后3换到1,到了初始位置了,结束,但是数组为[3,2,1,4]。当n和k%n有公因子的时候,就会出现这种问题。这个问题可以这样解决,找到n和k%n的最大公因子c,然后对数组的前c个数进行上述的迭代替换操作。这种方法的时间复杂度是O(n)。
贴上代码供大家参考:

public void rotate(int[] nums, int k) 
{
    if(nums.length == 0) return;
    k = k%nums.length;
    if(k < 1) return;
    int gcd = divisor(nums.length,k);
    for(int i = 0; i < gcd; i++)
    {
        int temp = nums[i];
        int tempIndex = i;
        while((tempIndex + k)%nums.length != i)
        {
            int theTemp = nums[(tempIndex + k)%nums.length];
            nums[(tempIndex + k)%nums.length] = temp;
            temp = theTemp;
            tempIndex = (tempIndex + k)%nums.length;
        }
        nums[i] = temp;
    }
    return;
}


int divisor(int m,int n)
{
     int temp;
     while(m%n!=0){
         temp=n;
         n=m%n;
         m=temp;
     }
     return n;
 }

当然咯,网上通用的做法是先reverse整个数组,然后对前k个和后面n-k个进行reverse,想法很好,但是值得注意的是相比我的方法,该方法可以让每个元素替换两次才到位的哟,其实它的时间复杂度是O(2n),但是这个方法省却了最大公约数的计算,也贴上代码供大家参考。

public void rotate(int[] nums, int k) 
{
    if(nums.length == 0)
    {
        return;
    }
    k = k%nums.length;
    reverse(nums,0,nums.length - 1);
    reverse(nums,0, k - 1);
    reverse(nums,k,nums.length - 1);
    return;
}

public void reverse(int[] nums, int head, int end)
{
    int temp;
    while(end > head)
    {
        temp = nums[end];
        nums[end] = nums[head];
        nums[head] = temp;
        ++head;
        --end;
    }
    return;
}

接下来,我们何妨看看链表的rotate操作,哈哈~~~
  
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值