字符串的排列組合問題

出處 http://blog.csdn.net/wuzhekai1985

問題1 :輸入一個字符串,打印出該字符串中字符的所有排列。例如輸入字符串abc,則輸出由字符abc所能排列出來的所有字符串abcacbbacbcacabcba

    思路:這是個遞歸求解的問題。遞歸算法有四個特性:(1)必須有可達到的終止條件,否則程序將陷入死循環;(2)子問題在規模上比原問題小;(3)子問題可通過再次遞歸調用求解;(4)子問題的解應能組合成整個問題的解。

    對於字符串的排列問題。如果能生成n - 1個元素的全排列,就能生成n個元素的全排列。對於只有1個元素的集合,可以直接生成全排列。全排列的遞歸終止條件很明確,只有1個元素時。下面這個圖很清楚的給出了遞歸的過程。


    參考代碼:解法1通過Permutation_Solution1(str, 0, n); 解法2通過調用Permutation_Solution2(str, str)來求解問題。

    //函數功能 : 求一個字符串某個區間內字符的全排列  
    //函數參數 : pStr爲字符串,begin和end表示區間  
    //返回值 :   無  
    void Permutation_Solution1(char *pStr, int begin, int end)  
    {  
        if(begin == end - 1) //只剩一個元素  
        {  
            for(int i = 0; i < end; i++) //打印  
                cout<<pStr[i];  
            cout<<endl;  
        }  
        else  
        {  
            for(int k = begin; k < end; k++)  
            {  
                swap(pStr[k], pStr[begin]); //交換兩個字符  
                Permutation_Solution1(pStr, begin + 1, end);  
                swap(pStr[k],pStr[begin]);  //恢復  
            }  
        }  
    }  
      
    //函數功能 : 求一個字符串某個區間內字符的全排列  
    //函數參數 : pStr爲字符串,pBegin爲開始位置  
    //返回值 :   無  
    void Permutation_Solution2(char *pStr, char *pBegin)  
    {  
        if(*pBegin == '\0')  
        {  
            cout<<pStr<<endl;  
        }  
        else  
        {  
            char *pCh = pBegin;  
            while(*pCh != '\0')  
            {  
                swap(*pBegin, *pCh);  
                Permutation_Solution2(pStr, pBegin + 1);  
                swap(*pBegin, *pCh);  
                pCh++;  
            }  
        }  
    }  
    //提供的公共接口  
    void Permutation(char *pStr)  
    {  
        Permutation_Solution1(pStr, 0, strlen(pStr));  
        //Permutation_Solution2(pStr,pStr);  
    }    <strong>
</strong>

問題2:輸入一個字符串,輸出該字符串中字符的所有組合。舉個例子,如果輸入abc,它的組合有a、b、c、ab、ac、bc、abc。

    思路:同樣是用遞歸求解。可以考慮求長度爲n的字符串中m個字符的組合,設爲C(n,m)。原問題的解即爲C(n, 1), C(n, 2),...C(n, n)的總和。對於求C(n, m),從第一個字符開始掃描,每個字符有兩種情況,要麼被選中,要麼不被選中,如果被選中,遞歸求解C(n-1, m-1)。如果未被選中,遞歸求解C(n-1, m)。不管哪種方式,n的值都會減少,遞歸的終止條件n=0或m=0。

    //函數功能 : 從一個字符串中選m個元素  
    //函數參數 : pStr爲字符串, m爲選的元素個數, result爲選中的  
    //返回值 :   無  
    void Combination_m(char *pStr, int m, vector<char> &result)  
    {  
        if(pStr == NULL || (*pStr == '\0'&& m != 0))  
            return;  
        if(m == 0) //遞歸終止條件  
        {  
            for(unsigned i = 0; i < result.size(); i++)  
                cout<<result[i];  
            cout<<endl;  
            return;  
        }  
        //選擇這個元素  
        result.push_back(*pStr);  
        Combination_m(pStr + 1, m - 1, result);  
        result.pop_back();  
        //不選擇這個元素  
        Combination_m(pStr + 1, m, result);  
    }  
    //函數功能 : 求一個字符串的組合  
    //函數參數 : pStr爲字符串  
    //返回值 :   無  
    void Combination(char *pStr)  
    {  
        if(pStr == NULL || *pStr == '\0')  
            return;  
        int number = strlen(pStr);  
        for(int i = 1; i <= number; i++)  
        {  
            vector<char> result;  
            Combination_m(pStr, i, result);  
        }  
    }    

問題3:打靶問題。一個射擊運動員打靶,靶一共有10環,連開10 槍打中90環的可能性有多少?

   思路:這道題的思路與字符串的組合很像,用遞歸解決。一次射擊有11種可能,命中1環至10環,或脫靶。

     參考代碼:

//函數功能 : 求解number次打中sum環的種數  
//函數參數 : number爲打靶次數,sum爲需要命中的環數,result用來保存中間結果,total記錄種數   
//返回值 :   無  
void ShootProblem_Solution1(int number, int sum, vector<int> &result, int *total)  
{  
    if(sum < 0 || number * 10 < sum) //加number * 10 < sum非常重要,它可以減少大量的遞歸,類似剪枝操作  
        return;  
    if(number == 1) //最後一槍  
    {  
        if(sum <= 10) //如果剩餘環數小於10,只要最後一槍打sum環就可以了  
        {  
            for(unsigned i = 0; i < result.size(); i++)  
                cout<<result[i]<<' ';  
            cout<<sum<<endl;  
            (*total)++;  
            return;  
        }  
        else  
            return;  
    }  
    for(unsigned i = 0; i <= 10; i++) //命中0-10環  
    {  
        result.push_back(i);  
        ShootProblem_Solution1(number-1, sum-i, result, total); //針對剩餘環數遞歸求解  
        result.pop_back();  
    }  
}  
//提供的公共接口  
void ShootProblem(int number, int sum)  
{  
    int total = 0;  
    vector<int> result;  
    ShootProblem_Solution1(number, sum, result, &total);  
    cout<<"total nums = "<<total<<endl;  
}  


發佈了9 篇原創文章 · 獲贊 32 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章