1. 程式人生 > >字串的排列與組合

字串的排列與組合

字串的全排列
題目:輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。
分析:對於這個問題可以把字串分成兩個部分,一部分是字串的第一個字元,另一部分是剩餘部分。即就是兩個步驟,1:求後面n-1個字元的全排列;2、把第一個字元與後面字元分別交換。而求後面n-1個字元的排列也可採用該方法,所以可以遞迴實現為:

vector<string> permutation(string s)
{
    vector<string> str;
    if(s.size()==0
) return str; permutation(s,0,str); return str; } void permutation(string s, int pbegin,vector<string>&str) { if(pbegin==s.size()) { str.push_back(s); cout<<s<<endl; } else { for(int i=pbegin;i<s.size();++i) { if
(i!=pbegin && s[i]==s[pbegin]) continue; swap(s[i],s[pbegin]); permutation(s,pbegin+1,str); swap(s[i],s[pbegin]); } } } /*另一種一樣的方法 void permutation(char* str,char* pbegin) { if (str==nullptr) { return; } if (*pbegin == '\0') printf("%s\n ", str); else { for (char* pctr = pbegin; *pctr != '\0'; ++pctr) { if (pctr!=pbegin && *pctr == *pbegin) continue; char c = *pctr; *pctr = *pbegin; *pbegin = c; permutation(str, pbegin + 1); c = *pctr; *pctr = *pbegin; *pbegin = c; } } } */

字串的組合
求輸入字元的組合,例如:輸入三個字元a、b、c則它們的組合有a、b、c、ab、ac、bc、abc。
分析:對於輸入n個字元,則這n個字元能夠構成長度為1、2、…、n的組合。在求長度為m的組合的時候,我們把這n個字元分成兩個部分:第一個字元和其餘所有的字元。如果組合裡面包含第一個字元,則就在剩餘字元裡面選取m-1個字元;如果組合裡面不包含第一個字元,則就在剩餘字元裡面選取m個字元。即可分解成兩個子問題求n-1中m-1的組合和求n-1中的m組合。實現如下:

vector<string> Combination(string s)
{
    vector<string> result;
    vector<string> str;
    if(s.size()==0)
        return result;
    for(int num=1;num<s.size();++num)
    {
        Combination(s,0,num,str,result);
    }
    return result;
}
void Combination(string s,int pbegin,int num,vector<char>&str,vector<string> &result)
{
    if(num==0)
    {
        string s;
        for(int i=0;i<str.size();++i)
            s+=str[i];
        result.push_back(s);
        cout<<s<<endl;
        return;
    }
    if(pbegin<s.size())
    {
        Combination(s,pbegin+1,num,str,result);
        str.push_back(s[pbegin]);
        Combination(s,pbegin+1,num-1,str,result);
        str.pop_back(s[pbegin]);
    }
}

NOTE :還可以使用next_permutation,是STL中提供的演算法,按字典序排列。

字串全排列拓展問題:
八皇后問題:在8×8的國際象棋上擺放八個皇后,使其不能相互攻擊,即任意兩個皇后不得處在同一行、同一列或者同一對角斜線上。下圖中的每個黑色格子表示一個皇后,這就是一種符合條件的擺放方法。請求出總共有多少種擺法。
分析:由於八個皇后的任意兩個不能處在同一行,那麼這肯定是每一個皇后佔據一行。於是我們可以定義一個數組ColumnIndex[8],陣列中第i個數字表示位於第i行的皇后的列號。先把ColumnIndex的八個數字分別用0-7初始化,接下來我們要做的事情就是對陣列ColumnIndex做全排列。由於我們是用不同的數字初始化陣列中的數字,因此任意兩個皇后肯定不同列。我們只需要判斷得到的每一個排列對應的八個皇后是不是在同一對角斜線上,也就是陣列的兩個下標i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。

字串組合問題拓展:
輸入兩個整數n和m,從數列1,2,3…n中隨意取幾個數,使其和等於m,要求列出所有的組合。

void find_factor(int sum, int n,vector<int>&rec, vector<vector<int>>&result)
{
    //遞迴出口  
    if (n <= 0 || sum <= 0)
        return;
    //輸出找到的數  
    if (sum == n)
    {
        rec.push_back(n);
        for (int i = 0; i<rec.size(); ++i)
            cout << rec[i] << " ";
        rec.pop_back();
        cout << endl;
        result.push_back(rec);
    }
    rec.push_back(n);
    find_factor(sum - n, n - 1,rec,result);//n放在裡面  
    rec.pop_back();
    find_factor(sum, n - 1, rec, result);//n不放在裡面  
}

int main(void)
{
    int sum, n;
    cin >> sum >> n;
    vector<vector<int>> result;
    vector<int> rec;
    cout << "所有可能的序列,如下:" << endl;
    find_factor(sum, n, rec, result);
    return 0;
}