LintCode - 旋轉(zhuǎn)字符串(普通)

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

難度:容易
要求:

給定一個字符串和一個偏移量,根據(jù)偏移量旋轉(zhuǎn)字符串(從左向右旋轉(zhuǎn))

樣例
對于字符串 "abcdefg".

offset=0 => "abcdefg"
offset=1 => "gabcdef"
offset=2 => "fgabcde"
offset=3 => "efgabcd"

思路

題目描述:
定義字符串的左旋轉(zhuǎn)操作:把字符串前面的若干個字符移動到字符串的尾部。
如把字符串a(chǎn)bcdef左旋轉(zhuǎn)2位得到字符串cdefab。
請實現(xiàn)字符串左旋轉(zhuǎn)的函數(shù),要求對長度為n的字符串操作的時間復(fù)雜度為O(n),空間復(fù)雜度為O(1)。
編程之美上有這樣一個類似的問題,咱們先來看一下:
設(shè)計一個算法,把一個含有N個元素的數(shù)組循環(huán)右移K位,要求時間復(fù)雜度為O(N),
且只允許使用兩個附加變量。
分析:
我們先試驗簡單的辦法,可以每次將數(shù)組中的元素右移一位,循環(huá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;
}
}
雖然這個算法可以實現(xiàn)數(shù)組的循環(huán)右移,但是算法復(fù)雜度為O(K * N),不符合題目的要求,要繼續(xù)探索。
假如數(shù)組為abcd1234,循環(huán)右移4位的話,我們希望到達的狀態(tài)是1234abcd。
不妨設(shè)K是一個非負的整數(shù),當K為負整數(shù)的時候,右移K位,相當于左移(-K)位。
左移和右移在本質(zhì)上是一樣的。
解法一:
大家開始可能會有這樣的潛在假設(shè),K<N。事實上,很多時候也的確是這樣的。但嚴格來說,我們不能用這樣的“慣性思維”來思考問題。
尤其在編程的時候,全面地考慮問題是很重要的,K可能是一個遠大于N的整數(shù),在這個時候,上面的解法是需要改進的。
仔細觀察循環(huán)右移的特點,不難發(fā)現(xiàn):每個元素右移N位后都會回到自己的位置上。因此,如果K > N,右移K-N之后的數(shù)組序列跟右移K位的結(jié)果是一樣的。
進而可得出一條通用的規(guī)律:
右移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;
}
}
可見,增加考慮循環(huán)右移的特點之后,算法復(fù)雜度降為O(N^2),這跟K無關(guān),與題目的要求又接近了一步。但時間復(fù)雜度還不夠低,接下來讓我們繼續(xù)挖掘循環(huán)右移前后,數(shù)組之間的關(guān)聯(lián)。

解法二:
假設(shè)原數(shù)組序列為abcd1234,要求變換成的數(shù)組序列為1234abcd,即循環(huán)右移了4位。比較之后,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個整體。右移K位的過程就是把數(shù)組的兩部分交換一下。
變換的過程通過以下步驟完成:
逆序排列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);
}
這樣,我們就可以在線性時間內(nèi)實現(xiàn)右移操作了。

  public class Solution {
    /**
     * @param str: an array of char
     * @param offset: an integer
     * @return: nothing
     */
    public void rotateString(char[] str, int offset) {
        if(str == null || str.length == 0){
            return;
        }
        
        int len = str.length;
        offset = offset % len;
        reverse(str, 0, len - offset - 1);
        reverse(str, len - offset, len - 1);
        reverse(str, 0, len - 1);
    }
    
    private void reverse(char[] str,int start,int end){
        for( ;start < end; start++,end--){
            char tmp = str[start];
            str[start] = str[end];
            str[end] = tmp;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容