我最近在阅读《 Programming Pearls》一书中的解决方案时,了解到 Juggling算法 如何在线性时间内旋转数组。
解决它的代码如下:
/*Function to left rotate arr[] of siz n by d*/ void leftRotate(int arr[], int d, int n) { int i, j, k, temp; for (i = 0; i < gcd(d, n); i++) { /* move i-th values of blocks */ temp = arr[i]; j = i; while(1) { k = j + d; if (k >= n) k = k - n; if (k == i) break; arr[j] = arr[k]; j = k; } arr[j] = temp; } }
关于此算法,我有两个问题-
我感觉到,我缺少有关 GCD 的工作, 模数 和 周期的 一些基本知识。
以下问题对我的第一个问题有解答,但仍然无法理解。
因此,如果有人可以通俗易懂地解释它以及他们如何凝聚在一起以使该算法起作用的原理,将很有帮助。
GCD如何确定旋转阵列所需的周期数?
因为内部循环以的步长递增d,并在返回起点时停止,即总跨度是的倍数n。那是LCM(n, d)。因此,该循环中的元素数为LCM(n, d) /d。这样的循环总数为n / (LCM(n, d) / d),等于GCD(n, d)。
d
n
LCM(n, d)
LCM(n, d) /d
n / (LCM(n, d) / d)
GCD(n, d)
为什么一旦完成一个循环,就从下一个元素开始新的循环,即下一个元素不能已经成为已处理循环的一部分?
否。内部循环以的步长递增d,是的倍数GCD(n, d)。因此,当我们开始第- i个周期时,我们需要(k*GCD + z) % n == i(for 0 <= z < i)命中。这导致(k*GCD) % n == (i - z)。这显然没有解决方案。
i
(k*GCD + z) % n == i
0 <= z < i
(k*GCD) % n == (i - z)