Leetcode第189题:旋转数组

1 问题描述

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

示例 1:
输入: [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]

示例 2:
输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]

说明:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
要求使用空间复杂度为 O(1) 的原地算法。

2 解题思路

2.1 多次翻转

如示例一所示,输入: [1,2,3,4,5,6,7] 和 k = 3。
整体翻转->[7,6,5,4,3,2,1]
左半部分(序号为0~k-1)翻转->[5,6,7,4,3,2,1]
右半部分(序号为k~size-1)翻转->[5,6,7,1,2,3,4]
得到最终输出->[5,6,7,1,2,3,4]
所有元素需全部遍历两遍,辅助空间为常数单位,时空复杂度分别为O(n)和O(1)。

2.2 直接右移

如示例一所示,输入: [1,2,3,4,5,6,7] 和 k = 3。

原有位置0123456
元素值1234567
新的位置0123456
元素值5671234

对于元素值为1、2、3、4,很容易看出 新的位置=原有位置+k
对于元素值为5、6、7,也不难看出 新的位置=(原有位置+k)%size
于是得到放置规则:
新的位置=(原有位置+k)%size
时空复杂度分别为O(n)和O(1)。
主要步骤:从下标0开始,将其放置到新的位置,同时将新的位置的元素放到他自己的新位置,如此循环,直到再次循环回下标0;对所有元素重复上述过程,直到所有元素都到了正确的位置。

2.3 写不动了T_T

2.4 需要注意的一些点

代码的鲁棒性,注意判断k的大小,会不会导致vector溢出,小于1返回,大于size做一下取余处理(代码问题描述根本没有写…还是得考虑周全)

3 C++代码

3.1 多次翻转

这个应该是最容易想到的方法了,剑指offer里面也有类似的翻转字符串的题目。
而且这个思路执行效率蛮高的,12ms,100%。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(k<1)
            return;
        
        int size=nums.size();
        
        //对k>size情况进行处理
        k%=size;
        
        //对nums整体翻转
        reverse(nums,0,size-1);
        //翻转前半部分
        reverse(nums,0,k-1);
        //翻转后半部分
        reverse(nums,k,size-1);
        
        return;
    }
    
    void reverse(vector<int>& nums,int low,int high){
      
        while(low<high){
            int temp=nums[low];
            nums[low++]=nums[high];
            nums[high--]=temp;
        }
        
        return;
    }
};

3.2 直接右移

这种思路执行效率也还可以,16ms,98.75%。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(k<1)
            return;
        
        int size=nums.size();
        k%=size;
        
        //count计数已经放到正确位置的元素数目
        //prePos指从前到后以此处理元素
        for(int prePos=0,count=0;count<size;++prePos){
            //prePos:当前元素位置,preVal:当前元素值
            //nextPos,nextVal同理
            int currentPos=prePos;
            int preVal=nums[prePos];
            
            //循环放置到正确的位置
            //直到循环回到开始位置
            do{
                int nextPos=(currentPos+k)%size;
                int nextVal=nums[nextPos];
                
                nums[nextPos]=preVal;
                preVal=nextVal;
                currentPos=nextPos;
                ++count;
            }while(currentPos!=prePos);
        }
        
        return;
    }
};

3.3 写不动了T_T

4 参考资料

1、Leetcode某个用户
2、LeetCode——旋转数组

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值