本文已参与「新人创作礼」活动,一起开启掘金创作之路。
轮转数组
189. 轮转数组 - 力扣(LeetCode) (leetcode-cn.com)
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:
输入: nums = [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:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
提示:
- 1 <= nums.length <= 10^5
- -2^31 <= nums[i] <= 2^31 - 1
- 0 <= k <= 10^5
进阶:
- 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
- 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
解题思路
通过取模运算完成数组逻辑上循环,将整个数组首尾相接,然后让每个元素向右跳k格,如果下一次的索引值超过了数组大小,由于取模运算索引值会落到数组大小范围之内。
运算步骤:
-
设置该轮首先要访问的索引值n,并与visited相比判断该索引值是否已经被访问。 注:visited是索引值,该索引值以及之后的索引值是一定会被访问的,所以visited一定是大于0且被访问的索引的最小值。
在循环数组中,每个元素向前跳k格,有2种情况出现:
- 第一种:每次跳k格,一轮过后,直接完成元素的轮转;
- 第二种:每次跳k格,一轮过后,有剩余元素未能完成元素的轮转,需要进行第二轮,这个时候第二轮的选择依据便是上一次首存访问的索引值加1但是必须小于visited。
-
计算某元素需要移动到的下一个索引值(next_index + k) % nums.size(), 如果下一个索引值已经被访问,则退出改轮,再次判断这一轮结束后是否所有的元素已经被访问,即n是否仍比visited小。
-
判断这个索引值是否已经被访问过
- 如果否,先判断,先保存该索引值的元素,然后用上一次的元素值覆盖。
- 如果是,n++,跳到步骤1
代码实现
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = 0;
int visited = -1;
while (visited == -1 || n < visited)
{
int temp;
int temp2 = nums[n];
int next_index = k + n;
if (visited == -1 || next_index < visited)
{
visited = next_index % nums.size();
}
do
{
if (visited == -1 || (next_index % nums.size() < visited && next_index % nums.size() != n))
{
visited = next_index % nums.size();
}
temp = nums[next_index % nums.size()];
nums[next_index % nums.size()] = temp2;
temp2 = temp;
next_index+=k;
}while (next_index % nums.size() != (k + n) % nums.size());
n++;
}
}
};