LeetCode 初级算法专题 旋转数组

79 阅读1分钟

here

这题一开始的思路时:先判断n是否是k的整数倍。若不是,以一个元素起循环往复地迭代,最终能够完成整个数组的迁移;若是整数倍,我只需要分别从0 -- k-1个元素分别迭代一系列,每系列n/k次便可完成任务。

还需要注意,如果k==0,不要动任何操作。

//错误代码。不过感觉这个save1和save2用的挺容易理解和精妙。
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(k==0) return ;
        int n=nums.size();
        if(n % k){
            int t=0,finish=0;
            int save1=nums[t],save2=-1;
            while(finish<=n){
                save2=nums[(t+k)%n];
                nums[(t+k)%n]=save1;
                save1=save2;
                t=(t+k)%n;
                finish++;
            }
        }
        else{
            for(int p=0;p<k;p++){
                int t=p,finish=0;
                int save1=nums[p],save2=-1;
                while(finish<=n/k){
                    save2=nums[(t+k)%n];
                    nums[(t+k)%n]=save1;
                    save1=save2;
                    t=(t+k)%n;
                    finish++;
                }
            }
        }
    }
};

这是行不通的,如下面的样例:

1,2,3,4,5,6
4

会发现卡在一个麦田怪圈里。改进方法在#2里。

1.数组部分旋转法

//先把整体数组倒置,然后把前k个倒置(0 -- k-1),再把剩下的倒置得到结果。
class Solution {
public:
    
    void rotate(vector<int>& nums, int k) {
        if(k==0) return ;
        int n = nums.size();
        for(int i=0,j=n-1;i<j;i++,j--){
            int rep=nums[i];
            nums[i]=nums[j];
            nums[j]=rep;
        }
        k%=n; //不要忽略对k求余,不然容易越界
        for(int i=0,j=k-1;i<j;i++,j--){
            int rep=nums[i];
            nums[i]=nums[j];
            nums[j]=rep;
        }
        for(int i=k,j=n-1;i<j;i++,j--){
            int rep=nums[i];
            nums[i]=nums[j];
            nums[j]=rep;
        }
        
    }
};

2. 约瑟夫环

/*
如果按从一个元素隔k步一直走下去,可能会形成闭环。也就是一部分元素右移了不止一遍,另一部分根本没动!
这个办法采取的办法是 走的总共步长是长度的整数倍时,直接尝试下一个数的闭环!

付出的时间虽然看着多但一定是值得的,重新拾起!
*/
class Solution {
public:
    
    void rotate(vector<int>& nums, int k) {
        int n = nums.size(); 
        k%=n;//进一步试图缩小
        if(k == 0) return ;
       
        if(n == 1) return ;//原封不动不用改的
        
        int count=0;
        int temp=nums[0];
        for(int cnt=0,i=k;cnt<n;i+=k,cnt++){
            int t=nums[i%n];
            nums[i%n] = temp;
            temp = t;//将终点预先存储的数据给temp作下次赋值准备

            if(i%n == count){//建议增长变量名防止犯错 错写成了i%k
                count++;
                i=count;
                temp=nums[i%n];//别忘了更新变量,这是赋值源,循环本轮结束后i+=k,那是赋值终点
            }
        }
    }
};