左旋轉字串

來源:互聯網
上載者:User

標籤:

組合語言中有一種移位指令叫做迴圈左移(ROL),現在有個簡單的任務,就是用字串類比這個指令的運算結果。對於一個給定的字元序列S,請你把其迴圈左移K位後的序列輸出。例如,字元序列S=”abcXYZdef”,要求輸出迴圈左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!

思路:三次翻轉:假設原數組序列為abcd1234,要求變換成的數組序列為1234abcd,即迴圈右移了4位。比較之後,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個整體。右移K位的過程就是把數組的兩部分交換一下。
變換的過程通過以下步驟完成:
 逆序排列abcd:abcd1234 → dcba1234;
 逆序排列1234:dcba1234 → dcba4321;
 全部逆序:dcba4321 → 1234abcd。

 1 class Solution { 2 public: 3     string LeftRotateString(string str, int n) { 4         int l=str.size(); 5         if(l<n) return str; 6         reverse(str,0,n-1); 7         reverse(str,n,l-1); 8         reverse(str,0,l-1); 9         return str;10     }11 private:12     void reverse(string &str,int left,int right){13         while(left<right){14             char c=str[left];15             str[left]=str[right];16             str[right]=c;17             left++;18             right--;19         }20     }21 };

第一節、左旋轉字串
題目描述:

定義字串的左旋轉操作:把字串前面的若干個字元移動到字串的尾部。
如把字串abcdef左旋轉2位得到字串cdefab。
請實現字串左旋轉的函數,要求對長度為n的字串操作的時間複雜度為O(n),空間複雜度為O(1)。 

編程之美上有這樣一個類似的問題,咱們先來看一下:

設計一個演算法,把一個含有N個元素的數組迴圈右移K位,要求時間複雜度為O(N),
且只允許使用兩個附加變數。

分析:

我們先實驗簡單的辦法,可以每次將數組中的元素右移一位,迴圈K次。
abcd1234→4abcd123→34abcd12→234abcd1→1234abcd。
RightShift(int* arr, int N, int K)
{
     while(K--)
     {
          int t = arr[N - 1];
          for(int i = N - 1; i > 0; i --)
               arr[i] = arr[i - 1];
          arr[0] = t;
     }
}

雖然這個演算法可以實現數組的迴圈右移,但是演算法複雜度為O(K * N),不符合題目的要求,要繼續探索。

假如數組為abcd1234,迴圈右移4位的話,我們希望到達的狀態是1234abcd。
不妨設K是一個非負的整數,當K為負整數的時候,右移K位,相當於左移(-K)位。
左移和右移在本質上是一樣的。

解法一:
大家開始可能會有這樣的潛在假設,K<N。事實上,很多時候也的確是這樣的。但嚴格來說,我們不能用這樣的“慣性思維”來思考問題。
尤其在編程的時候,全面地考慮問題是很重要的,K可能是一個遠大於N的整數,在這個時候,上面的解法是需要改進的。
仔細觀察迴圈右移的特點,不難發現:每個元素右移N位後都會回到自己的位置上。因此,如果K > N,右移K-N之後的數組序列跟右移K位的結果是一樣的。

進而可得出一條通用的規律:
右移K位之後的情形,跟右移K’= K % N位之後的情形一樣,如代碼清單2-34所示。
//代碼清單2-34
RightShift(int* arr, int N, int K)
{
     K %= N;
     while(K--)
     {
          int t = arr[N - 1];
          for(int i = N - 1; i > 0; i --)
               arr[i] = arr[i - 1];
          arr[0] = t;
     }
}
可見,增加考慮迴圈右移的特點之後,演算法複雜度降為O(N^2),這跟K無關,與題目的要求又接近了一步。但時間複雜度還不夠低,接下來讓我們繼續挖掘迴圈右移前後,數組之間的關聯。


解法二:
假設原數組序列為abcd1234,要求變換成的數組序列為1234abcd,即迴圈右移了4位。比較之後,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個整體。右移K位的過程就是把數組的兩部分交換一下。
變換的過程通過以下步驟完成:
 逆序排列abcd:abcd1234 → dcba1234;
 逆序排列1234:dcba1234 → dcba4321;
 全部逆序:dcba4321 → 1234abcd。
虛擬碼可以參考清單2-35。
//代碼清單2-35
Reverse(int* arr, int b, int e)
{
     for(; b < e; b++, e--)
     {
          int temp = arr[e];
          arr[e] = arr[b];
          arr[b] = temp;
     }
}

RightShift(int* arr, int N, int k)
{
     K %= N;
     Reverse(arr, 0, N – K - 1);
     Reverse(arr, N - K, N - 1);
     Reverse(arr, 0, N - 1);
}

這樣,我們就可以線上性時間內實現右移操作了。

稍微總結下:
編程之美上,
(限制書中思路的根本原因是,題目要求:“且只允許使用兩個附加變數”,去掉這個限制,思路便可如泉噴湧)
1、第一個想法 ,是一個字元一個字元的右移,所以,複雜度為O(N*K)
2、後來,它改進了,通過這條規律:右移K位之後的情形,跟右移K’= K % N位之後的情形一樣
複雜度為O(N^2)
3、直到最後,它才提出三次翻轉的演算法,得到線性複雜度。

下面,你將看到,本章裡我們的做法是:
1、三次翻轉,直接線性
2、兩個指標逐步翻轉,線性
3、stl的rotate演算法,線性

好的,現在,回到咱們的左旋轉字串的問題中來,對於這個左旋轉字串的問題,咱們可以如下這樣考慮:
1.1、思路一:

對於這個問題,咱們換一個角度,可以這麼做:
將一個字串分成兩部分,X和Y兩個部分,在字串上定義反轉的操作X^T,即把X的所有字元反轉(如,X="abc",那麼X^T="cba"),那麼我們可以得到下面的結論:(X^TY^T)^T=YX。顯然我們這就可以轉化為字串的反轉的問題了。

不是麼?ok,就拿abcdef 這個例子來說(非常簡短的三句,請細看,一看就懂):
1、首先分為倆部分,X:abc,Y:def;
2、X->X^T,abc->cba, Y->Y^T,def->fed。
3、(X^TY^T)^T=YX,cbafed->defabc,即整個翻轉。

我想,這下,你應該瞭然了。
然後,代碼可以這麼寫(已測試正確):

 

    1. //[email protected] 小橋流水 && July  
    2. //c代碼實現,已測試正確。  
    3. //http://www.smallbridge.co.cc/2011/03/13/100%E9%A2%98  
    4. //_21-%E5%B7%A6%E6%97%8B%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2.html  
    5. //July、updated,2011.04.17。  
    6. #include <stdio.h>  
    7. #include <string.h>  
    8. char * invert(char *start, char *end)  
    9. {     
    10. char tmp, *ptmp = start;      
    11. while (start != NULL && end != NULL && start < end)    
    12.     {     
    13.         tmp = *start;     
    14.         *start = *end;        
    15.         *end = tmp;       
    16.         start ++;     
    17.         end --;   
    18.     }  
    19. return ptmp;  
    20. }  
    21. char *left(char *s, int pos)   //pos為要旋轉的字元個數,或長度,下面主函數測試中,pos=3。  
    22. {  
    23. int len = strlen(s);  
    24.     invert(s, s + (pos - 1));  //如上,X->X^T,即 abc->cba  
    25.     invert(s + pos, s + (len - 1)); //如上,Y->Y^T,即 def->fed  
    26.     invert(s, s + (len - 1));  //如上,整個翻轉,(X^TY^T)^T=YX,即 cbafed->defabc。  
    27. return s;  
    28. }  
    29. int main()  
    30. {     
    31. char s[] = "abcdefghij";      
    32.     puts(left(s, 3));  
    33. return 0;  
    34. }  

轉自:http://blog.csdn.net/zhoushuai520/article/details/7703368

左旋轉字串

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.