標籤:style blog http color 使用 strong
如,abcde左移3位為deabc
要求時間複雜度O(n),空間複雜度O(1),每一個字元只能遍曆一次
摘自http://blog.csdn.net/geniusluzh/article/details/8460031
利用數學解決該問題
其實對於這道題,最初一看的想法就是將當前位依次替換左移m位對應的那個位,然後依次替換。後來發現有的情況一次迴圈替換就能全部完成整個串的左移,而有的情況下會出現多個迴圈鏈,一時只得到規律,不能想到很好的證明辦法,只怪以前初等數論沒有好好學啊!
我們發現對於長度為n的串,左移m位,會形成gcd(n, m)個鏈,這裡的gcd就是大家熟知的最大公約數,每個鏈的長度顯然就是n/(gcd(n, m))。我們如何來證明這個問題呢?我們令i+j*m 和 i+k*m正好走了一圈又指向同一個元素,那麼便是(i+j*m)%n == (i+k*m)%n,因此根據同餘的性質我們知道n | (k-j)*m,而n = n‘ * gcd(n, m), m = m‘ * gcd(n, m)。所以我們得到n‘ | (k-j) * m‘, 由於n‘ 和 m‘ 互素,因此 n‘ | (k - j),因此我們知道最小的k-j = n‘ = n/gcd(n, m),也就是說一個迴圈鏈裡頭有n/gcd(n, m)個元素,因此總共有gcd(n, m)個迴圈鏈,於是得證。因此我們只需要取前gcd(n, m)個元素,每個走一條鏈進行迴圈的替換就行了。其實這個演算法是最優的,真正的O(N)的時間複雜度,而且沒有額外的開銷。
int gcd(int m, int n){ if(m < n){ int t = m; m = n; n = t; } int r = m%n; while(r){ m = n; n = r; r = m%n; } return n;} char* leftShift(char* str, int n, int k){ char s, t; int g = gcd(n,k),len = n / g; for(int i = 0; i < g; ++i){ s = str[i]; for(int j = 0; j < len; ++j){ t = str[(n - k + i)%n]; str[(n - k + i)%n] = s; s = t; i = (n - k + i)%n; times++; } } return str;}
本文基於知識共用署名-非商業性使用 3.0 許可協議進行許可。歡迎轉載、演繹,但是必須保留本文的署名林羽飛揚,若需諮詢,請給我發信