劍指Offer38 - 字串的排列 - [DFS]
阿新 • • 發佈:2021-06-22
題目:
輸入一個字串,打印出該字串中字元的所有排列。
你可以以任意順序返回這個字串陣列,但裡面不能有重複元素。
思路:
一個很直觀的思路,對於任意一個字串,例如"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!)$。