劍指Offer詳解之左旋轉字符串
(1)暴力移位法
這種方法可能是最直觀,最容易想出的方法。但這也是最壞的方法。時間複雜度挺高,用這種方法容易超時。
這種方法是一位一位的移動實現左旋轉操作。
【代碼】
#include <stdio.h> #include <malloc.h> #include <string.h> char *str; char* Reverse(char* str,int n){ if(str == NULL || n < 0){ return ""; } int len = strlen(str); int i; char temp; //循環左移n位 while(n--){ //左移 //保存第一個字符 temp = str[0]; for(i = 1;i < len;i++){ str[i-1] = str[i]; } str[len-1] = temp; } return str; } int main() { int i,n; str = (char*)malloc(sizeof(char)*1001); while(scanf("%s",str) != EOF){ scanf("%d",&n); //左旋轉 str = Reverse(str,n); //輸出 for(i = 0;i < strlen(str);i++){ printf("%c",str[i]); } printf("\n"); }//while return 0; }
UDBOJ 4對上述字符串循環左移4次,8次,12次。。。。。(n % len )效果是一樣的
左移次數:n % len n原始左移次數 len字符串長度
【代碼】
char* Reverse(char* str,int n){ if(str == NULL || n < 0){ return ""; } int len = strlen(str); int i; char temp; //對左移次數進行優化 n = n % len; //循環左移n位 while(n--){ //左移 //保存第一個字符 temp = str[0]; for(i = 1;i < len;i++){ str[i-1] = str[i]; } str[len-1] = temp; } return str; }
(2)指針翻轉法
咱們先來看個例子,如下:
abcdefghi,若要讓abc移動至最後的過程可以是:abcdefghi->defabcghi->defghiabc
如此,我們可定義倆指針,p1指向ch[0],p2指向ch[m];
一下過程循環m次,交換p1和p2所指元素,然後p1++, p2++;。
第一步,交換abc 和def ,abcdefghi->defabcghi
第二步,交換abc 和ghi,defabcghi->defghiabc
整個過程,看起來,就是abc作為一組一步一步向後移動
abcdefghi
defabcghi
defghiabc
//最後的 複雜度是O(m+n)
abcdefghi,若要讓abc移動至最後的過程可以是:abcdefghi->defabcghi->defghiabc
如此,我們可定義倆指針,p1指向ch[0],p2指向ch[m];
一下過程循環m次,交換p1和p2所指元素,然後p1++, p2++;。
第一步,交換abc 和def ,abcdefghi->defabcghi
第二步,交換abc 和ghi,defabcghi->defghiabc
整個過程,看起來,就是abc作為一組一步一步向後移動
abcdefghi
defabcghi
defghiabc
//最後的 複雜度是O(m+n)

由上述例子九個元素的序列abcdefghi,您已經看到,m=3時,p2恰好指到了數組最後一個元素,每m個一組正好一一對應。於是,上述思路沒有問題。但是每m個一組有剩餘時怎麼辦?假設abcde,還能如上麵的方法解決嗎?這樣就不可以了,那樣就數組越界了。所以我們要特殊處理尾部不夠m個一組的元素。
就舉這個例子,對abcdefghij序列進行左旋轉操作:
如果abcdefghij要變成defghijabc:
1. defabcghij
2. defghiabcj //最後一個j不夠一組m個要單獨處理
3. defghiabjc //我們需要一次一次交換移至前麵
4. defghiajbc
5. defghijabc
下麵,再針對上述過程,畫個圖清晰說明下,如下所示:
如果abcdefghij要變成defghijabc:
1. defabcghij
2. defghiabcj //最後一個j不夠一組m個要單獨處理
3. defghiabjc //我們需要一次一次交換移至前麵
4. defghiajbc
5. defghijabc
下麵,再針對上述過程,畫個圖清晰說明下,如下所示:


總結:
1、首先讓p1=ch[0],p2=ch[m],即讓p1,p2相隔m的距離,可以理解為每m個一組,第一組和後每組對應交換;
2、判斷p2+m-1是否越界,即判斷最後一組是不是構成一組。如果不能構成一組就不能一一對應交換,如果沒有越界轉到3,否則轉到4。
3、不斷交換*p1與*p2,然後p1++,p2++,循環m次,然後轉到2。
4、此時p2+m-1已經越界,即最後一組不能構成一組,不能一一對應交換,需處理尾巴。
過程如下:
4.1 通過n-p2得到p2與尾部之間元素個數r,即我們要前移的元素個數。
4.2 以下過程執行r次:
ch[p2]<->ch[p2-1],ch[p2-1]<->ch[p2-2],....,ch[p1+1]<->ch[p1];p1++;p2++;
所以,之前最初的那個左旋轉九個元素abcdefghi的思路在末尾會出現問題的(如果p2後麵有元素就不能這麼變,例如,如果是處理十個元素,abcdefghij?對的,就是這個意思),解決方法:
def ghi abc jk
當p1指向a,p2指向j時,由於p2+m越界,那麼此時p1,p2不要變
這裏p1之後(abcjk)就是尾巴,處理尾巴隻需將j,k移到abc之前,得到最終序列,代碼編寫如下:
1、首先讓p1=ch[0],p2=ch[m],即讓p1,p2相隔m的距離,可以理解為每m個一組,第一組和後每組對應交換;
2、判斷p2+m-1是否越界,即判斷最後一組是不是構成一組。如果不能構成一組就不能一一對應交換,如果沒有越界轉到3,否則轉到4。
3、不斷交換*p1與*p2,然後p1++,p2++,循環m次,然後轉到2。
4、此時p2+m-1已經越界,即最後一組不能構成一組,不能一一對應交換,需處理尾巴。
過程如下:
4.1 通過n-p2得到p2與尾部之間元素個數r,即我們要前移的元素個數。
4.2 以下過程執行r次:
ch[p2]<->ch[p2-1],ch[p2-1]<->ch[p2-2],....,ch[p1+1]<->ch[p1];p1++;p2++;
所以,之前最初的那個左旋轉九個元素abcdefghi的思路在末尾會出現問題的(如果p2後麵有元素就不能這麼變,例如,如果是處理十個元素,abcdefghij?對的,就是這個意思),解決方法:
def ghi abc jk
當p1指向a,p2指向j時,由於p2+m越界,那麼此時p1,p2不要變
這裏p1之後(abcjk)就是尾巴,處理尾巴隻需將j,k移到abc之前,得到最終序列,代碼編寫如下:
#include <stdio.h> #include <malloc.h> #include <string.h> char *str; void Reverse(char* str,int n){ if(str == NULL || n <= 0){ return; } int len = strlen(str); int pre = 0; int p = n; char temp; //len % n n個一組,不夠一組的個數 //len - n - len % n 表示總個數減去最前一組減去最後不夠一組的個數 //交換次數 int count = len - n - len % n; while(count--){ //交換 temp = str[pre]; str[pre] = str[p]; str[p] = temp; pre++; p++; } //處理最後尾部不夠一組的元素 //rear為尾部左移元素個數 int rear = len - p; while(rear--){ //左移 int i = p; while(i > pre){ temp = str[i]; str[i] = str[i-1]; str[i-1] = temp; i--; } p++; pre++; } } int main() { int i,n; str = (char*)malloc(sizeof(char)*1001); while(scanf("%s",str) != EOF){ scanf("%d",&n); //左旋轉 //注意一下n需要取餘就可以了,不能超過字符串自身的長度 n = n % strlen(str); Reverse(str,n); //輸出 for(i = 0;i < strlen(str);i++){ printf("%c",str[i]); } printf("\n"); }//while return 0; }
(3)三步翻轉法

/********************************* * 日期:2013-12-02 * 作者:SJF0115 * 題號: 題目1362:左旋轉字符串(Move!Move!!Move!!!) * 來源:https://ac.jobdu.com/problem.php?pid=1362 * 結果:AC * 來源:劍指Offer * 總結: **********************************/ #include <stdio.h> #include <malloc.h> #include <string.h> char *str; //反轉單詞 void ReverseWord(char* words,int begin,int end){ int temp; if(words == NULL || begin > end || begin < 0){ return; } //反轉 while(begin < end){ temp = words[begin]; words[begin] = words[end]; words[end] = temp; begin ++; end --; } } char* Reverse(char* str,int n){ if(str == NULL || n < 0){ return ""; } int len = strlen(str); //分成兩部分(1)前n項(2)剩餘項 //反轉前n個 ReverseWord(str,0,n-1); //反轉剩餘 ReverseWord(str,n,len-1); //全部反轉 ReverseWord(str,0,len-1); return str; } int main() { int i,n; str = (char*)malloc(sizeof(char)*1001); while(scanf("%s",str) != EOF){ scanf("%d",&n); //左旋轉 //注意一下n需要取餘就可以了,不能超過字符串自身的長度 n = n % strlen(str); str = Reverse(str,n); //輸出 for(i = 0;i < strlen(str);i++){ printf("%c",str[i]); } printf("\n"); }//while return 0; }
自己按自己思路有改動。
最後更新:2017-04-03 14:54:29