189. 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].

Note:
Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.

[show hint]

Hint:
Could you do it in-place with O(1) extra space?

Related problem: Reverse Words in a String II

分析

将n个元素向右移动k步,可能出现k=0,k>=n,k<n的情况,所以对k取模,当k=0或者k是n的倍数时,结果为零,此时移动k步相当于没动,直接返回;否则k值即为一个小于n的需要移动的步数,声明两个vector分别保存移动后的前半部分以及后半部分,即末尾的k个元素为新数组的前半部分,其余的为后半部分,顺序不变,然后对原数组进行赋值和插入操作。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k=k%nums.size();
        if(k==0)
            return;
        vector<int> front(nums.end()-k,nums.end());
        vector<int> last(nums.begin(),nums.end()-k);
        nums=front;
        nums.insert(nums.end(),last.begin(),last.end());
    }
};

这种方法占用过多的额外空间,下面介绍一种占用常数个额外空间的方法。

以k步向右移动元素,则这些元素会形成一个环路,只需对下标进行(index+k)%n运算,即可沿着环路遍历各元素。但由于k值设定的关系,可能会将n个元素分成两个没有交集的环路,故需要记录当前环路的起始位置,当该环路走回起点时,移动元素之后需要将目标位置前进一步,如果只有一个环路,那么所有元素都遍历过了,外层循环会结束,否则外层循环继续,目标位置指向了下一个环路的起点,然后进行一些初始化的操作,继续遍历新的环路。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int size=nums.size();
        k=k%size;
        if(k==0)
            return;
        int nex_index=(0+k)%size;//记录当前元素要移动到的目标位置
        int value=nums[0];//记录当前移动的元素值
        int start=0;//记录开始位置
        for(int i=0;i<size;i++)//每个元素都要遍历一次
        {
            if(nex_index==start)//当目标位置与开始位置一样时,说明走完了一个环路
            {
                nums[nex_index]=value;//对目标位置赋值
                nex_index=(nex_index+1)%size;//防止有多个环路的情况,令目标位置前进一步,置为下一个环路的开始位置
                value=nums[nex_index];//记录下一个环路的开始元素
                start=nex_index;//记录下一个环路的开始位置
                nex_index=(nex_index+k)%size;//记录下一个环路首元素将要移动到的目标位置
            }
            else//在当前环路中移动元素
            {
                int tmp=nums[nex_index];//暂存目标位置的元素
                nums[nex_index]=value;//移动当前元素
                value=tmp;//当前元素赋值为目标位置元素,即为下一个要移动的元素
                nex_index=(nex_index+k)%size;//目标位置后移
            }
        }
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值