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。
原有位置 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
元素值 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
新的位置 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
元素值 | 5 | 6 | 7 | 1 | 2 | 3 | 4 |
对于元素值为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;
}
};