题目
给定一个数组,将数组中的元素向右移动 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) 的 原地 算法。
来源:力扣(LeetCode) 著作权归作者所有。
思路
- 首先的思路,题目规定只能使用原地算法不开辟其它空间,那就一个一个移动,一次往后挪动一位,总共挪动k次,二重循环。
然后超时了 - 是看题解学到的写法:三次反转,首先将所有元素反转,再反转前k个元素,再反转后n-k个元素,就可以成功旋转数组。
如示例1:
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4 --> 得到结果
- 循环替换:理解了很久,可以理解成同学换座位。每个同学往右移动k个位置,第1个同学去到第k+1个位置,第k+1个位置的同学被挤开,就得去到它的后k个位置,最终有一个同学坐到一个空位置上(没有同学被挤开)。但是这时候并不能保证所有同学的位置都换好了,就得从第2个同学继续开始往右换位置。计算每次成功换位置的数量,每有一个同学成功换位置就cnt++,当cnt与数组长度相等时,就说明所有同学都成功换位置,结束循环。
代码
- 暴力法(超出时间限制)
34 / 35 个通过测试用例
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
int tmp;
k=k%len;
while(k--){
tmp=nums[len-1];
for(int i=len-1;i>0;i--){
nums[i]=nums[i-1];
}
nums[0]=tmp;
}
}
};
- 三次反转
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k=k%nums.size();
reverse(nums.begin(),nums.end());
reverse(nums.begin(),nums.begin()+k);
reverse(nums.begin()+k,nums.end());
}
};
- 环状替换
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
k=k%len;
int prev,tmp,next,cur,cnt=0;
for(int start=0;cnt<len;start++){
cur=start;
prev=nums[cur];
do{
next=(cur+k)%len;
tmp=nums[next];
nums[next]=prev;
prev=tmp;
cur=next;
cnt++;
}while(cur!=start);
}
}
};