leetcode 189. 旋转数组
问题描述
给定一个数组,将数组中的元素向右移动 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) 的 原地 算法。
代码1
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(k == 0) return;
int i,tmp[k],n = nums.size();
k %= n;
for(i = 0; i < k; i++)
{
tmp[i] = nums[n-k+i];
}
for(i = n-k-1; i >= 0; i--)
{
nums[i+k] = nums[i];
}
for(i = 0; i < k; i++)
{
nums[i] = tmp[i];
}
}
};
多使用了\(O(k)\)的空间,明显不符合题目要求。结果:
执行用时 :8 ms, 在所有 C++ 提交中击败了80.09%的用户
内存消耗 :10 MB, 在所有 C++ 提交中击败了5.00%的用户
代码2
根据(i + k) % n = 旋转后的位置,可以将原有数组中的数据复制到新数组中
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(k == 0) return;
int i,n = nums.size();
vector<int> ans;
ans.resize(n);
k %= n;
for(i = 0; i < n; i++)
{
ans[(i+k)%n] = nums[i];
}
for(i = 0; i < n; i++)
{
nums[i] = ans[i];
}
}
};
多使用了\(O(n)\)的空间,结果
执行用时 :8 ms, 在所有 C++ 提交中击败了80.09%的用户
内存消耗 :10.1 MB, 在所有 C++ 提交中击败了5.00%的用户
代码3
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k %= n;
if(k == 0) return;
int nextval,curind,curval,nextind,cnt = 0;
for(int start = 0; cnt < n; start++)
{
curind = start;
curval = nums[curind];
nextind=(curind+k)%n;
do{
nextval = nums[nextind];
nums[nextind] = curval;
curind = nextind;
curval = nextval;
nextind = (curind+k)%n;
cnt++;
}while(curind != start);
}
}
};
结果
执行用时 :8 ms, 在所有 C++ 提交中击败了80.09%的用户
内存消耗 :10.2 MB, 在所有 C++ 提交中击败了5.26%的用户
分析:以 nums= [0 1 2 3 4 5 6],k = 3为例,下标交换顺序为 0 -> 3 -> 6 -> 2 -> 5 -> 1 -> 4 -> 0,具体过程如下:
[start 1 2 0 4 5 6] -> [start 1 2 0 4 5 3] -> [start 1 6 0 4 5 3]
| | | | | |
curind=3 nextind nextind curind=6 curind=2 nextind
-> [start 1 6 0 4 2 3] -> [start 5 6 0 4 2 3] -> [start 5 6 0 1 2 3]
| | | | |
nextind curind=5 curind=1 nextid curind=0
但存在一个问题,如果k是n的约数的话,会有元素遍历不到,例如nums=[0 1 2 3 4 5],k=2,则遍历的下标为0 -> 2 -> 4 - > 0,显然1,3,5没有遍历到,需要将start=1后再循环一遍。