给定一个整数数组 nums
,将数组中的元素向右轮转 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]
void rotate(int* nums, int numsSize, int k)
{
int tmp[numsSize];
for(int i=0;i<numsSize;i++)//遍历整个数组
{
tmp[(i+k)%numsSize]=nums[i];//原数组下标为i,新数组下标就为i+k,但是还有最后可能越界就进行取模,就刚刚好为新下标
}
for(int i=0;i<numsSize;i++)//把额外数组还回去
{
nums[i]=tmp[i];
}
}
环状替代我觉得还不如这个好写(主要我没看懂)
我们可以将被替换的元素保存在变量 temp 中,从而避免了额外数组的开销。
我们从位置 0 开始,最初令 temp=nums[0]。根据规则,位置 0 的元素会放至 (0+k)modn 的位置,令 x=(0+k)modn,此时交换 temp 和 nums[x],完成位置 x 的更新。然后,我们考察位置 x,并交换 temp 和 nums[(x+k)modn],从而完成下一个位置的更新。不断进行上述过程,直至回到初始位置 0。
容易发现,当回到初始位置 0 时,有些数字可能还没有遍历到,此时我们应该从下一个数字开始重复的过程,可是这个时候怎么才算遍历结束呢?我们不妨先考虑这样一个问题:从 0 开始不断遍历,最终回到起点 0 的过程中,我们遍历了多少个元素?
由于最终回到了起点,故该过程恰好走了整数数量的圈,不妨设为 a 圈;再设该过程总共遍历了 b 个元素。因此,我们有 an=bk,即 an 一定为 n,k 的公倍数。又因为我们在第一次回到起点时就结束,因此 a 要尽可能小,故 an 就是 n,k 的最小公倍数 lcm(n,k),因此 b 就为 lcm(n,k)/k。
这说明单次遍历会访问到 lcm(n,k)/k 个元素。为了访问到所有的元素,我们需要进行遍历的次数为
gcd(n,k)
其中 gcd 指的是最大公约数。