力扣-旋转数组-关于环状替换理解
题目链接
个人理解
首先比较难理解的是an=bk
首先你可以把数组想象成一个圆桌,每个人需要走到正确的位置,使得数组满足要求。
而这个等式就是为了计算他们走的路程。
首先假设解决n=5,k=2的问题。
- an:
相当于1先去2的位置,发现不是自己的位置,继续走一步,发现3就是需要的位置,就停下来了,3站起来找自己应该在的位置,过程跟1一样。因为要求的最后是回到起点,所以他们走的路程是圈的整数倍(你都一步一步走了,怎么可能还不是n的整数倍),且每个位置显然不会被多次访问(哪有换好了,你还去要别人对的位置)。所以这样走的路程是an
- bk
相当于这次不一个个问了,它直接多走一步,去到目的地,那么每个元素走k步,遍历了b个元素,走了bk步。
两种的路程你肯定要满足路程一样,所以an=bk。
所以an为n和k的倍数,既然不会重复访问一个元素,那肯定你的整个an都是最小的(多了就冗余了),所以an=lcm(n,k)。
你每次访问的元素个数 b = l c m ( n , k ) k \large b=\frac{lcm(n,k)}{k} b=klcm(n,k),你不会重复访问,所以循环次数可以求出为 n b = n k l c m ( n , k ) = g c d ( n , k ) \large \frac{n}{b}=\frac{nk}{lcm(n,k)}=gcd(n,k) bn=lcm(n,k)nk=gcd(n,k).即n和k的最大公倍数。
同时停止这一圈即你又返回了开始的位置
如果你还是不太明白,你可以试着画出n=5,k=2以及n=6,k=2,(一个五边形,一个六边形),前一个只需要一圈,后一个需要2圈
力扣官方源码
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k = k % n;
if(k<0){
return;
}
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);
}
}
};
参考
-
力扣题解(https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/)
-
https://www.jianshu.com/p/569aab1d7c36