題目描述:
輸入一個字符串,
按字典序打印出該字符串中字符的所有排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。
求全排列:
思路如圖所示:
還有一個問題要注意,就是如果字符串中有重復的字符串
由於全排列就是從第一個數字起,每個數分別與它后面的數字交換,我們先嘗試加個這樣的判斷——如果一個數與后面的數字相同那么這兩個數就不交換 了。例如abb,第一個數與后面兩個數交換得bab,bba。然后abb中第二個數和第三個數相同,就不用交換了。但是對bab,第二個數和第三個數不 同,則需要交換,得到bba。由於這里的bba和開始第一個數與第三個數交換的結果相同了,因此這個方法不行。
換種思維,對abb,第一個數a與第二個數b交換得到bab,然后考慮第一個數與第三個數交換,此時由於第三個數等於第二個數,所以第一個數就不再用與第三個數交換了。再考慮bab,它的第二個數與第三個數交換可以解決bba。此時全排列生成完畢!
這樣,我們得到在全排列中去掉重復的規則:
去重的全排列就是從第一個數字起,每個數分別與它后面非重復出現的數字交換。
字典序全排列
上面的思路求出了全排列,但不能保證是字典序。得到字典序有兩種方式:
- 對全排列結果進行排序
- 對初始字符串排序,然后在遞歸的過程中將全排列的交換兩個元素改為兩者之間的元素移位。
排序方法代碼:
1 class Solution { 2 public: 3 vector<string> Permutation(string str) { 4 if(str.size() == 0) 5 return vector<string>(); 6 //sort(str.begin(),str.end()); 7 vector<string> ret; 8 Permutation(str, 0, ret); 9 sort(ret.begin(), ret.end()); 10 return ret; 11 } 12 13 void Permutation(string str, int begin, vector<string> &ret){ 14 if(begin == str.size()){ 15 ret.push_back(str); 16 return; 17 } 18 set<char> charset; // 可能有重復元素 19 for(int i=begin; i<str.size(); ++i) 20 if(i==begin || charset.count(str[i]) == 0){ 21 charset.insert(str[i]); 22 swap(str[begin], str[i]); 23 Permutation(str, begin+1, ret); 24 swap(str[begin], str[i]); 25 } 26 } 27 };
不用對結果排序:
class Solution { public: vector<string> Permutation(string str) { if(str.size() == 0) return vector<string>(); sort(str.begin(),str.end()); vector<string> ret; Permutation(str, 0, ret); return ret; } void Permutation(string str, int begin, vector<string> &ret){ if(begin == str.size()){ ret.push_back(str); return; } set<char> charset; // 可能有重復元素 for(int i=begin; i<str.size(); ++i) if(i==begin || charset.count(str[i]) == 0){ charset.insert(str[i]); string str1 = shift(str, begin, i); Permutation(str1, begin+1, ret); str1 = str; } } string shift(string str, int left, int right){ char tmp = str[right]; for(int i=right; i>left; --i) str[i] = str[i-1]; str[left] = tmp; return str; } };