title: 2019-8-24 字符串的排列
tags: 算法,每日一題,字符串
字符串的排列
1. 題目描述
輸入一個字符串,按字典序打印出該字符串中字符的所有排列,輸入一個字符串,長度不超過9(可能有字符重複),字符只包括大小寫字母。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。
2.題目解析
首先對於給定的一個字符串比如abc,對於第一個位置我們可以有三種選擇,a,b,c。所以只需要每次都把字符串對應的字符換到第一個位置即可。比如現在我們把b換到了第一個位置bac
,那麼這個時候相當於固定了第一個位置的字符了,對於後面的字符的處理就和之前的一樣了(ok構成了遞歸了)。因此只要遞歸下去就可以解決問題了。但是這是沒有考慮字符串中有重複元素的情況。
對於字符串中包含重複字符的情況,我們可能會嘗試如果要交換的字符相同的我們就不交換,但是對於abb
,第一次aa交換不變,第二次ab交換得到bab
,第三次bba
。顯然第三次的遞歸會得到一個bba
的結果,第二次的bab
也會得到一個bba
的結果。所以這種嘗試是無效的。現在嘗試策略二:在當前這次遞歸中,如果從from到當前交換的位置之間都沒有相同的元素(保證之前沒有出現固定當前元素的情況)。
這兩個問題解決之後還有一個問題就是按照字典序輸出,這需要在每次進行下一次遞歸之前對從from到to之間的元素進行一次字典排序即可。
2.1 思路解析
1、只考慮全排列的情況
2、考慮用重複的情況
錯誤的方式,相同的字符不交換
正確的情況:從交換位置處i
到from
之間如果有和i相同的字符就不交換也不會遞歸下去
3、需要字典排序的字符串全排列
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> res;
if(str.empty()) return res;
sort(str.begin(), str.end());
permutation_recru(str, 0, str.size()-1, res);
return res;
}
void permutation_recru(string& str,int from, int to, vector<string>& res){
if(from == to) {
res.push_back(str);
return;
}
for(int i=from; i<=to; ++i){
sort(str.begin() + from, str.end());//這個只能放在這個位置
if(isSwap(str, from, i)){
swap(str, from, i);
permutation_recru(str, from+1, to, res);
swap(str, from, i);
}
}
}
void swap(string& str, int a, int b){
char temp = str[a];
str[a] = str[b];
str[b] = temp;
}
bool isSwap(string& str, int from, int to){
for(int i=from; i<to; ++i){
if(str[i] == str[to]) return false;
}
return true;
}
};
更多關於編程和機器學習資料請關注FlyAI公衆號。