1. 程式人生 > 其它 >劍指Offer38 - 字串的排列 - [DFS]

劍指Offer38 - 字串的排列 - [DFS]

題目:

輸入一個字串,打印出該字串中字元的所有排列。

你可以以任意順序返回這個字串陣列,但裡面不能有重複元素。

思路:

一個很直觀的思路,對於任意一個字串,例如"abcde",我首先列舉選定首字元,例如先選定了首字元是"a",那剩下部分的怎麼permutation的事情就交給函式permutation("bcde")好了。

一旦我得到了permutation("bcde")的結果,我只要把所有的"bcde"的排列前面都拼接上一個字元"a"即可。

然後,選定首字元是"b",剩下的工作交給permutation("acde")。

再然後,選定首字元是"c",剩下的工作交給permutation("abde")。

以上一個主幹思路。

然後需要注意的一個小的問題是,permutation結果不能出現重複,上面的思路在遇到"aacbb"這種字串裡有重複字元的時候會導致permutation結果重複。

顯然,我們只需要選定首字元時做一下篩選,首字元選"a"只選一次,選"b"的時候也只選一次,即可。

這個的話,考慮字串不一定只有小寫字母,因此可以先對"aacbb"做一次排序,得到"aabbc",然後遍歷選取首字母的時候跳過重複的即可。

Code:

class Solution
{
public:
    vector<string> permutation(string s)
    {
        vector
<string> res = {}; if (s.empty()) return res; sort(s.begin(), s.end()); return perm(s); } vector<string> perm(const string &s) { vector<string> res = {}; if (s.length() == 1) { res.push_back(s);
return res; } char previous = s[0] + 1; for (int i = 0; i < s.length(); i++) { if (s[i] == previous) continue; string other = s.substr(0, i) + s.substr(i + 1); vector<string> temp_result = permutation(other); for (int j = 0; j < temp_result.size(); j++) res.push_back(s[i] + temp_result[j]); temp_result.clear(); previous = s[i]; } return res; } };

時間複雜度:

在最開始需要做一個$O(n \log n)$的排序。

後面的遞迴,記permutation長度為n的字串的時間複雜度為$f(n)$,

有 $f(n) = n \cdot f(n - 1)$,根據 $f(1) = 1$,易得 $f(n) = n!$。

所以時間複雜度 $O(n \log n + n!) = O(n!)$。