求職面試 左旋轉字串(C 版)

2022-02-10 18:26:28 字數 4177 閱讀 6634

題目描述:

定義字串的左旋轉操作:把字串前面的若干個字元移動到字串的尾部。

如把字串abcdef左旋轉2位得到字串cdefab。

請實現字串左旋轉的函式,要求對長度為n的字串操作的時間複雜度為o(n),空間複雜度為o(1)

首先第一種最直觀的解法:把陣列字元乙個個的左移:

class leftrotatestring

\r\nresult:

", str, result);

console.read();

}public

string method1a(string str, int k)

chararray[chararray.length - 1] = firstchar;

}return

newstring(chararray);

}}

注意,string型別是不可變的,如果你用str[0] = str[1],不能編譯通過。

雖然功能可以實現,但是演算法複雜度為o(k * n),不符合要求。繼續探索。

大家開始可能會有這樣的潛在假設,k

尤其在程式設計的時候,全面地考慮問題是很重要的,k可能是乙個遠大於n的整數,在這個時候,上面的解法是需要改進的。

仔細觀察迴圈右移的特點,不難發現:每個元素右移n位後都會回到自己的位置上。因此,如果k > n,右移k-n之後的陣列序列跟右移k位的結果是一樣的。

進而可得出一條通用的規律:

右移k位之後的情形,跟右移k』= k % n位之後的情形一樣

public

string method1b(string str, int k)

chararray[chararray.length - 1] = firstchar;

}return

newstring(chararray);

}

這只是**技巧~~演算法複雜度降為o(n^2),達不到o(n)的要求。

三次翻轉法:

假設原陣列序列為abcd1234,要求變換成的陣列序列為1234abcd,即迴圈右移了4位。比較之後,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個整體。左移k位的過程就是把陣列的兩部分交換一下。

變換的過程通過以下步驟完成:

逆序排列abcd:abcd1234 → dcba1234;

逆序排列1234:dcba1234 → dcba4321;

全部逆序:dcba4321 → 1234abcd。

public

void reverse(char chararray, int begin, int end)

}public

string leftshift(string str, int k)

ok, 到這裡為止,總算滿足條件了,演算法複雜度為o(2n) = o(n)。

我在想,為什麼能想出這樣好的點子呢?這裡用到了線性代數矩陣的知識。哈哈,這裡體現到數學的力量了!

我們還是把字串看成有兩段組成的,記位xy。左旋轉相當於要把字串xy變成yx。我們先在字串上定義一種翻轉的操作,就是翻轉字串中字元的先後順序。把x翻轉後記為xt。顯然有(xt)t=x。

我們首先對x和y兩段分別進行翻轉操作,這樣就能得到xtyt。接著再對xtyt進行翻轉操作,得到(xtyt)t=(yt)t(xt)t=yx。

那麼,到此結束了麼?no,要是到此結束,那就失去樂趣了。

題目是限制空間複雜度o(1),那麼如果不限制呢?哈哈,那就太簡單了。

public

string method2(string str, int k)

for (int i = str.length - k, j = 0; i < str.length; i++, j++)

return

newstring(chararray);

}

時間複雜度就是o(n),但是空間複雜度是o(k)了。可惜了,不符合題目要求啊,不過這樣以空間換時間的做法還是挺好的。

難道就沒有更好的方法了麼?難道就沒有強大的數學公式解法之類的?

好吧,讓我們反向從結果看看有木有什麼規律。

對於"abcdefg" 左移3來說,你看結果,會發現這樣神奇的規律:

public

string leftshift2(string str, int k)

通過這一連串的賦值,就可以用o(n)的時間複雜度和o(1)的空間複雜度來解決。但是這是針對"abcdefg"左移3實現的。

我們需要擴充套件到一般應用。其實從結果我們可以看出來了,這一系列的賦值關鍵是index的計算。

聰明同學應該發現了規律——index是乙個迴圈鏈,當index>str.length時,指標又從左開始(取模運算),前乙個end 就變成現在的start。

於是我很快的寫出了這個程式:

///

///此**有bug

///public

string leftshiftwrong(string str, int k)

chararray[end] = temp;

return

newstring(chararray);

}

我很高興,它的結果

對於"abcdefg" 左移3來說是正確的。

但是沒過多久,我在午休小憩的時候,靈光一閃,這個程式有個嚴重的bug,對於"abcdef"左移2來說,結果是錯的!(不知道你有沒有靈光一閃呢?我發現自己在程式設計的時候總是沒有,但是當我休息的時候卻會有靈光一閃。看來還得多休息啊!!!)

原因在於對於

"abcdefg" 左移3來說,3和7是互為質數的,除不盡,因此整個迴圈鏈一直串起來。

但是對於

"abcdef"左移2來說,2和6不是互為質數的,有最大公約數2,迴圈鏈會在0的時候斷掉。需要繼續下一條迴圈鏈。

可以看看

"abcdef"左移2的手工解法:

public

string leftshift2(string str, int k)

從中可以看出,這種情況,應該有多條子迴圈鏈。條數 = k 和 str.length的 最大公約數。

於是,終於可以寫成正確並且高效的程式了:

///

///左移字串。時間複雜度o(n), 空間複雜度o(1)

///public

string leftshiftcorrect(string str, int k)

else

}return

newstring(chararray);

}

完了麼?沒完。接下來我擴充套件成通用的陣列迴圈移位:

///

///陣列迴圈移位。時間複雜度o(n), 空間複雜度o(1)

///k>0為左移,k

<0為右移

///public

void shift(t array, int k)

else

}}

哎,你說了,這玩意有嘛用啊?花了這兩天搞這玩意,有意思麼?

」愛你一萬年」--剪下成「一萬年愛你」,就可以用上面陣列的迴圈移位演算法實現。

其實從結果分析,最終的字串"

愛你一萬年"內容沒變,只是輸出順序變了,而我們上面的演算法呢,不管怎麼做,都是要移動字串。時間複雜度最少為o(n)。那麼能不能不移動字串內容呢,用乙個強大的公式,來輸出新的順序呢?

有時候,從純演算法角度走到頭了,我們必須換個思路,以資料結構的方式來解決問題。

於是,我就構建了下面這個資料結構,來實現旋轉後順序的輸出。公式很簡單,就是自己計算什麼時候是第乙個要輸出的index。

class rotatestructure

public

void shift(int k)

public t this[int index]

}public ienumerableoutput()

}

於是,這樣就實現了時間複雜度o(1),空間複雜度o(1)的演算法呢。

呵呵,差不多暫時到這邊了。

那個,誰有好工作推薦啊?求南京地區的 .net開發,要求就一條,技術含量高的,團隊氣氛活躍的,有發展前景的啊!

C 左旋轉字串

問題描述 定義字串的左旋轉操作 把字串前面的若干個字元移動到字串的尾部,如把字串 abcd 左旋轉 2 位得到字串 cdab 請實現字串左旋轉的函式。演算法分析 1.暴力移位法 a 把最後乙個字元取出並儲存起來,然後z最後乙個字元前面的所有字元後移,b 儲存的最後乙個字元存放到第乙個字元的位置,c ...

左旋轉字串

題目 定義字串的左旋轉操作 把字串前面的若干個字元移動到字串的尾部。如把字串abcdef左旋轉2位得到字串cdefab。請實現字串左旋轉的函式。要求時間對長度為n的字串操作的複雜度為o n 輔助記憶體為o 1 思想 旋轉三次 include include using namespace std v...

左旋轉字串

package com.string 旋轉字串 q 26 左旋轉字串 題目 定義字串的左旋轉操作 把字串前面的若干個字元移動到字串的尾部。如把字串abcdef左旋轉2位得到字串cdefab。請實現字串左旋轉的函式。要求時間對長度為n的字串操作的複雜度為o n 輔助記憶體為o 1 public cla...