这题一开始的思路时:先判断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,那是赋值终点
}
}
}
};