题目来源:
https://leetcode-cn.com/problems/rotate-array/description/
描述:
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例:
输入: [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]
思路:
思路一:
参考示例,利用vector特性,只需要将7,6,5依次插入vector首部即可。这个涉及内存再分配,很耗时间的.
思路二:
很经典的思路,数组整体移动考虑用数组反转,还是上述示例
第一步:反转前几位 [4,3,2,1,5,6,7]
第二步:反转整个数组[7,6,5,1,2,3,4]
第三步:反转前几位 [5,6,7,1,2,3,4]
思路三:
还是用参考示例,来[1,2,3,4,5,6,7]向右移动三位的话,首先元素1占据元素4的位置,然后元素2占据了元素5的位置。这样需要新数组能暂存4,5,6,7的值。需要o(n)个变量来暂存。 此时,如何做到只用一个变量暂存呢?
[1,2,3,4,5,6,7]
[1,2,3,1,5,6,7] 把元素4暂存
这里是重点,只用一个变量暂存!方法就是把元素4填入新的位置,然后再暂存新元素
[1,2,3,1,5,6,4] 把4放入新位置,4就可以不暂存了,变量直接存储新元素7.然后依次类推。
什么时候截止?由于每个元素都要移动一次,所以循环n次(n为数组大小)
这样就结束了吗?考虑一种情况,举例[1,2,3,4,5,6]向右移动2个位置
[1,2,3,4,5,6]
[1,2,1,4,5,6]暂存3
[1,2,1,4,3,6]暂存5
[5,2,1,4,3,6]暂存1
继续移动发现一直是1,3,5三个元素在移动。所以当移动开头位置时,向后跳一格,2所在位置作为新开头位置。对2进行新循环移动
[5,2,1,2,3,6]暂存4
[5,2,1,2,3,4]暂存6
[5,6,1,2,3,4]暂存2 。 此时移动了6次,总循环结束。
代码:
思路一:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
size_t size = nums.size();
if (size == 0) return;
for (int i = 0; i < k%size; ++i) {
nums.insert(nums.begin(),nums[size - 1]);
}
nums.resize(size);
}
};
思路二:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
size_t size = nums.size();
if (size == 0) return;
k %= size;
if (k == 0) return;
reverse(nums,0,size-1-k);
reverse(nums,0,size-1);
reverse(nums,0,k-1);
}
//对数组中位置i和j之间的所有元素进行反转[i,j]
void reverse(vector<int>& nums,int i,int j){
int size = nums.size();
if (i < 0 || i >= size || j < 0 || j >=size) return;
while (i < j){
int temp = nums[i];
nums[i++] = nums[j];
nums[j--] = temp;
}
}
};
思路三:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int begin = 0;
int step = 0;
int i = 0;
int cur;
int bak = nums[0];
size_t size= nums.size();
while(step++ < size){
i = (i + k) % size;
cur = bak;
bak = nums[i];
nums[i] = cur;
if (i == begin){
begin++;
i++;
bak = nums[i];
}
}
}
};