【演算法基礎】字串的全排列演算法
題目描述
輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。
輸入描述
輸入一個字串,長度不超過9(可能有字元重複),字元只包括大小寫字母。
這道題是劍指offfer中一道經典的題,如果有n個元素,我們就能有n*(n - 1)個全排列,n為1時,只有一個全排列
舉個栗子,當字串為ABC時,分析一下全排列的過程:
1.固定A在字串的最左邊,然後全排列B和C
2.全排列B和C
3.當全排列的字串只有一個字元時,它的全排列就是它自身
4.當固定A後,其他字串的全排列完畢後,把A與其他字元進行交換,然後重複上面的步驟進行全排列
示意圖如下:
基於這種思路,我使用回溯法解決,程式碼如下:
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> ret;
if (str.empty()) {
return ret;
}
string tmp = "";
_permutation(str, ret, tmp, 0);
return ret;
}
private:
void _permutation(string str, vector<string>& ret, string& tmp, int begin) {
if (begin == str.size()) {
ret.push_back(tmp);
return;
}
for (int i = begin; i < str.size(); ++i) {
if (i != begin && str[i] == str[begin])
continue;
swap(str[i], str[begin]);
tmp += str[begin];
_permutation(str, ret, tmp, begin + 1);
tmp.pop_back();
}
}
};
這裡主要解釋一下這個函式:
void _permutation(string str, vector<string>& ret, string& tmp, int begin) {
if (begin == str.size()) {
ret.push_back(tmp);
return;
}
for (int i = begin; i < str.size(); ++i) {
if (i != begin && str[i] == str[begin])
continue;
swap(str[i], str[begin]);
tmp += str[begin];
_permutation(str, ret, tmp, begin + 1);
tmp.pop_back();
}
}
這個函式的思路就是上面的思路,使用回溯法,思路如下
1. 讓當前字元去和每個字串交換
2.交換完成後,遞迴的呼叫函式去處理除當前字元之外剩下的字元
遞迴的出口就是begin等於str.size(),這時候的tmp(因為一直在儲存每一個字元),就是一個全排列的結果,儲存在陣列ret之中
注意,在迴圈中有這麼一個判斷:
if (i != begin && str[i] == str[begin])
continue;
這個判斷主要是處理字串中有重複字元的
去重的全排列就是從第一個數字起,每個數分別與它後面非重複出現的數字交換
在這個迴圈遍歷時,有兩種情況str[i]和str[begin]相等,一種是i和begin相等,即同一個元素,一種是相同的元素
這時候如果交換的話沒有意義,就不用交換並且儲存了,不然就會出現重複的結果
舉個栗子,當字串為aabb時,如果註釋掉這句話,ret的結果是
如果不註釋掉,結果是正確的:
如果要按照字典序輸出的話,還需要對陣列ret進行排序
再介紹一種簡單的方法,如果為了快速AC的話,可以使用STL中的next_permutation函式,函式定義如下:
template <class BidirectionalIterator>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last);
template <class BidirectionalIterator, class Compare>
bool next_permutation (BidirectionalIterator first,
BidirectionalIterator last, Compare comp);
解決的程式碼如下:
vector<string> Permutation(string str) {
vector<string> answer;
if(str.empty())
return answer;
sort(str.begin(),str.end());
do{
answer.push_back(str);
}
while(next_permutation(str.begin(),str.end()));
return answer;
}
這個函式的文件連結如下:
http://www.cplusplus.com/reference/algorithm/next_permutation/?kw=next_permutation
---------------------
作者:Qregi
來源:CSDN
原文:https://blog.csdn.net/Qregi/article/details/82049298
版權宣告:本文為博主原創文章,轉載請附上博文連結!