LeetCode 189. Rotate Array

Description

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

Examples

1、
Input: [1,2,3,4,5,6,7] and k = 3
Output: [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]


2、
Input: [-1,-100,3,99] and k = 2
Output: [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]

Notes

思路一:想到了时间O(n)空间O(1)的做法,就是按照隔k个数两两交换,等到数组n个元素都做过交换时,就交换完毕。但有一个细节想了很久,就是当我们完成一轮交换后,若未完成整个过程,那么下一轮交换的该从哪里开始?例如,我们如果在第一个元素开始循环,等第一轮循环结束,此时还没交换完n个元素,那我们应该开始第二轮交换,但第二轮交换从哪个位置开始呢?若从第二个元素开始第二轮循环,会不会产生第二个元素在第一轮已经被交换过了的情况呢?若第二个元素已在第一轮被后移k,则第二轮从第二个元素开始必定会产生错误。
答案是:第二轮一定从第二个元素开始。为什么呢?因为如果在第一轮中回到过第二个元素,那么肯定存在一个循环模式,使得若干次后,当前位置相对于起点(第一个元素),后移了一个位置,那么将这个模式继续下去,则一定会经过第三第四…个位置,那么交换就在第一轮完成了,所以会产生矛盾。因此若在第一轮未完成交换,那么,第二个元素肯定没被后移过。同理,若第二轮未完成交换第三个元素肯定没被后移过…那么总共需要几轮循环呢?应该是数组长度len和后移步长k的最大公约数(自己推的不一定对,而且在代码中并不需要这个结论)。
思路二是看题解别人的思路,用三次对称交换,很巧妙。复杂度应该和第一种一样。

Codes

思路一

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int len=nums.size();
        if(!len) return;
        k=k%len;
        if(!k) return;
        int cnt=0;
        for(int i=0;i<k;++i)
        {
            int tempindex=i;
            int temp=nums[i];
            while((tempindex+k)%len!=i)
            {
                tempindex=(tempindex+k)%len;
                int t=nums[tempindex];
                nums[tempindex]=temp;
                temp=t;
                cnt++;
            }
            nums[i]=temp;
            cnt++;
            if(cnt>=len) break;
        }
        return;
    }
};

思路二,利用三次对称变换。

class Solution {
public:
    void reverse(vector<int>& nums,int left,int right)
    {
        int mid=(right+left)/2;
        for(int i=left;i<=mid;++i)
        {
            int temp=nums[i];
            nums[i]=nums[right-(i-left)];
            nums[right-(i-left)]=temp;
        }
        return;
    }
    void rotate(vector<int>& nums, int k) {
        int len=nums.size();
        if(!len) return;
        k=k%len;
        if(!k) return;
        reverse(nums,0,len-k-1);
        reverse(nums,len-k,len-1);
        reverse(nums,0,len-1);
        return;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值