关于循环移动,编程之美中曾提到一种手摇法,即需要三次循环,进行2n-3次swap,时间O(n),空间O(1),今天在这一题的Discuss上看到一个大神“3 lines of C++ in one pass using swap”帖子,点了进去发现一个非常神奇算法,虽然是2重循环,但实际只有n-1次swap,这里将大神的英文帖子翻译一下:
原帖链接:https://oj.leetcode.com/discuss/26501/3-lines-of-c-in-one-pass-using-swap
void rotate(int nums[], int n, int k) {
for (; k %= n; n -= k)
for (int i = 0; i < k; i++)
swap(*nums++, nums[n - k]);
}
每一次swap会将1个数调整好位置,所以总的运行时间是O(n)的,例如:
一开始,nums[] = [1,2,3,4,5,6,7], n = 7, k = 3
第1次外层循环之后,会得到nums[] 变为[4,1,2,3],n变为4,k变为3
第2次外层循环之后,nums[]变为[4],n变为1,k变为0
循环结束
这一模一减似乎做了很多事,不知道这是为什么,于是自己又举了个例子:
一开始nums[] = [1,2,3,4,5,6,7], n = 7, k = 5
第1次外层循环之后,会得到nums[]变为[3,4,5,6,7,2,1],n变为2,k变为1
第2次外层循环之后,会得到nums[]变为[3,4,5,6,7,1,2],n变为1,k变为0
循环结束
-------------------------------------------------------------------------------------- YY分割线 -----------------------------------------------------------------------------------------
感觉像减治法,但又说不上为什么,算法思想是找到当前位置应该是哪个数,即nums[n - k],然后进行交换,然后前k个数已经到位,还需要调整后面n-k个,为什么后面这n-k个数,又相当于是 k’ % n‘ 循环移位呢,YY一下,是不是因为这k个数swap到位时,最初的n-k个数调到了最后,并且做了k%(n-k)的循环移位,我们再对其进行k%(n-k)的循环移位实际上是将其相对位置进行恢复的操作,貌似有点意思,不过为什么最初的n-k个数做了k%(n-k)的循环移位呢,这是因为每一次swap,都将最前面的一个数调到了最后,呼呼,貌似YY的还有根有据的样子O(∩_∩)O~