''' mbinary ######################################################################### # File : rotate.py # Author: mbinary # Mail: zhuheqin1@gmail.com # Blog: https://mbinary.xyz # Github: https://github.com/mbinary # Created Time: 2018-05-19 21:54 # Description: three methods of rotating a list 1. 利用 ba=(br)^T(ar)^T=(arbr)^T,通过三次反转字符串: 即首先对序列前部分逆序,再对序列后部分逆序,再对整个序列全部逆序 2. 分组交换(尽可能使数组的前面连续几个数为所要结果):a长度大于b,将 ab 分成 a0a1b,交换 a0 和 b,得 ba1a0,只需再交换 a1和 a0。若 a 长度小于 b,将 ab 分成 ab0b1,交换 a 和 b0,得 b0ab1,只需再交换 a 和b0。通过不断将数组划分,和交换,直到不能再划分为止。分组过程与求最大公约数很相似。 3.所有序号为 (j+i*m) % n (j 表示每个循环链起始位置,i 为计数变量,m 表示左旋转位数,n 表示字符串长度),会构成一个循环链(共有 gcd(n,m)个,gcd 为 n、m 的最大公约数),每个循环链上的元素只要移动一个位置即可,最后整个过程总共交换了 n 次(每一次循环链,是交换 n/gcd(n,m)次,总共 gcd(n,m)个循环链。所以,总共交换 n 次)。 ######################################################################### ''' def rotate(s, k, right=False): def reverse(a, b): while a < b: s[a], s[b] = s[b], s[a] a += 1 b -= 1 n = len(s) k = k % n if not right else n-k % n reverse(0, k-1) reverse(k, n-1) reverse(0, n-1) return s def rotate2(s, k, right=False): def swap(a, b, c): for i in range(c): s[a+i], s[b+i] = s[b+i], s[a+i] def _rot(pl, pr): ''' swap s[pl,pr) , s[pr:]''' if pr == n: return if pr-pl <= n-pr: swap(pl, pr, pr-pl) _rot(pr, 2*pr-pl) else: swap(pl, pr, n-pr) _rot(n-pr+pl, pr) n = len(s) k = k % n if not right else n-k % n _rot(0, k) return s def rotate3(s, k, right=False): def gcd(a, b): if b == 0: return a return gcd(b, a % b) n = len(s) k = k % n if not right else n-k % n r = gcd(n, k) for i in range(r): tmp = s[i] j = (i+k) % n while j != i: s[j-k] = s[j] j = (j+k) % n s[(j-k+n) % n] = tmp return s def test(): def f(func, *args, right=False): print(' '.join(['testing:', func.__name__, str(args), 'right=', str(right)])) rst = func(*args, right=right) print('result', rst) print() return f if __name__ == '__main__': s = [i for i in range(10)] tester = test() tester(rotate, s, 4, right=True) tester(rotate, s, 4) tester(rotate2, s, 2, right=True) tester(rotate2, s, 2) tester(rotate3, s, 132, right=True) tester(rotate3, s, 132) ''' testing: rotate ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4) right= True result [6, 7, 8, 9, 0, 1, 2, 3, 4, 5] testing: rotate ([6, 7, 8, 9, 0, 1, 2, 3, 4, 5], 4) right= False result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] testing: rotate2 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 2) right= True result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7] testing: rotate2 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 2) right= False result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] testing: rotate3 ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 132) right= True result [8, 9, 0, 1, 2, 3, 4, 5, 6, 7] testing: rotate3 ([8, 9, 0, 1, 2, 3, 4, 5, 6, 7], 132) right= False result [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] '''