旋转数组
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/problems/rotate-array
来源:力扣(LeetCode)
题目描述:
给定一个数组,将数组中的元素向右移动 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]
解题思路说明:
只针对自己看过一遍没有理解的算法进行简单说明:
方法3:使用环状替换
当时这个方法想了好几天,都没有理解,最后在网上看到大佬通过多边形讲解,感觉自己突然悟了。
使用此方法有两种情况:
case 1:数组为[1, 2, 3, 4, 5], k = 2;
此时正确答案为4 5 1 2 3,对应的索引index改变顺序为1->3->5->2->4->1,为了方便写代码,可以看作index从1转了一圈,回到了起始位置,即此时index % n == 1,其中n为数组元素个数.我们用五边形的顶点表示数组中的元素,五边形如下图所示:
case 2:数组为[1, 2, 3, 4, 5, 6],如果继续按照上述方法,从第一个元素开始,索引index每次+k,则会出现1->3->5->1,此时循环已经结束,但是我们才交换了一半元素。解决方法也很简单,将初始的index+1,继续循环一遍,此时循环过程为2->4->6->2,其余的元素也被遍历了。不难看出,第一次循环终止的条件依旧是index % n == 1,第二次为index % n == 2。从而可以新加一个变量start表示index开始的位置,内循环开始位置为start,内循环终止条件改为index % n == start,每次内循环结束后,start加一。在内循环过程中,使用count变量记录交换次数,程序结束的条件为count>=n.雾霾用六边形的顶点表示数组中的元素,如下所示:
如果大家不能理解这个算法,可以跟着6变形的边走一遍。
方法4:使用反转
这个方法基于这个事实:当我们旋转数组 k 次, k%n个尾部元素会被移动到头部,剩下的元素会被向后移动。
答案v1.0
class Solution {
public:
void rotate(vector<int>& nums, int k) {
// 方法1:暴力反转,超出时间限制
/*int temp = 0;
int preEle = 0;
for (int i = 0; i < k; i++)
{
preEle = nums[nums.size() - 1];
for (int j = 0; j < nums.size(); j++)
{
temp = nums[j];
nums[j] = preEle;
preEle = temp;
}
}*/
// 方法2:使用新的数组
// 1. 使用push_back()实现。
/*vector<int> temp;
k = k % nums.size();
for (int i = nums.size() - k; i < nums.size(); i++)
{
temp.push_back(nums[i]);
}
for(int i = 0; i < nums.size() - k; i++)
{
temp.push_back(nums[i]);
}
for (int i = 0; i < nums.size(); i++)
{
nums[i] = temp[i];
}*/
// 2,使用循环索引a
/*vector<int> temp;
k = k % nums.size();
for (int i = 0; i < nums.size(); i++)
{
temp.push_back(nums[(i + nums.size() - k) % nums.size()]);
}
for (int i = 0; i < nums.size(); i++)
{
nums[i] = temp[i];
}*/
// 2,使用循环索引b
/*vector<int> temp(nums.size(), 0);
k = k % nums.size();
for (int i = 0; i < nums.size(); i++)
{
temp[(i + k) % nums.size()] = nums[i];
}
for (int i = 0; i < nums.size(); i++)
{
nums[i] = temp[i];
}*/
// 3.使用环状替换
/*int count = 0; //交换元素的次数
int index = 0;//开始元素的位置
k = k % nums.size();
while (count < nums.size())
{
int preEle = nums[index];
for (int i = index + k; i % nums.size() != index; i += k)
{
int temp = nums[i % nums.size()];
nums[i % nums.size()] = preEle;
preEle = temp;
count++;
}
nums[index] = preEle;
count++;
index++;
}
*/
// 方法4:使用反转
k = k % nums.size();
reverse(nums.begin(), nums.end()); //第一次翻转,翻转所有元素
reverse(nums.begin(), nums.begin() + k);//翻转前k个元素
reverse(nums.begin() + k, nums.end());// 翻转后面n - k个元素
}
};