在循环过程中,从位置0开始进行移动,位置0的元素会放在x=(0 + k) % n的位置上,为了不再次开辟空间,我们在数组上直接进行元素的交换,这样完成了位置0的元素值和位置x的元素值,然后在x位置上进行上述的循环过程,即x1=(x + k) % n,交换x位置和x1位置的元素值,不断进行循环,直到回到初始位置0.
但是,我们容易发现,在回到初始位置0的时候,有可能出现有元素没有被遍历到的情况,这个时候我们应该从下一个元素开始重复上述的循环过程。所以这时候要确定两个条件,一个是确定结束循环的条件,另一个是确定结束整个循环的条件。
确定结束循环的条件比较好理解,当初始位置的索引不等于循环过程中的索引就一直进行本轮的循环,换一句话说当循环过程中的索引等与本轮循环的初始位置的索引时,就停止本轮的循环。
确定结束整个循环的条件需要知道要进行多少轮的循环,我们将从初始位置循环再到初始位置的过程中遍历的所有元素个数设为b,题中给出需要移动的位数为k,数组的长度为n,从初始位置循环再到初始位置这个过程中走过数组的圈数设为a,所以可以知道an=bk。即an一定为n,k的公倍数。因为在每轮的循环过程中,只要回到初始位置我们就停止本轮的循环,所以a的值要求最小,故an就是n,k的最小公倍数bk=an=nk的最小公倍数。所以bk=nk的最小公倍数,所以b=nk的最小公倍数/k,因为b是从初始位置循环再到初始位置的过程中遍历的所有元素个数,n是数组中用元素的个数,故a=n/b -> a=n/nk的最小公倍数=nk/nk的最小公倍数。
以下代码来自力扣方法二
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k = k % n;
int count = gcd(k, n);
for(int start = 0; start < count; start++) {
int current = start;
int prev = nums[start];
do {
int next = (current + k) % n;
swap(nums[next], prev);
current = next;
} while(start != current);
}
}
};