字符串的所有組合


  我在之前的一篇文章中,寫的是關於全排列問題的小結(http://www.cnblogs.com/wangkundentisy/p/8570082.html),這篇文章主要介紹的為字符串的組合問題。首先需要弄清楚排列和組合的區別,對於字符串"abc",它的全排列包括:abc、acb、bac、bca、cab、cba。但它的所有組合為:a、b、c、ab、ac、bc、abc。也就是說一個長度為n的字符串,它的組合包括長度為1~n的所有字符子串(忽略順序)。下面具體探討一下字符串的組合問題的實現。

  在求長度為n的字符串的組合時,我們要遍歷從1到n所有的子串,當求長度為m(1≤m≤n)的組合時,可以把那個字符分成兩部分:第一個字符和其余所有的字符。此時就分為兩種情況了:

(1)組合包含第一個字符,則下一步在剩余字符里選取m-1個字符。

(2)組合不包含第一個字符,則下一步在剩余的n-1個字符中選取m個字符。

很明顯,這個用遞歸實現比較清晰。總的來說,可以把求n個字符組成對的長度為m的組合問題分成兩個子問題,即分別求n-1個字符中長度為m-1的組合;以及求n-1個字符中長度為m的組合。

代碼如下:

#include<iostream>
#include<cassert>
#include<vector>
#include<stack>
#include<unordered_map>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

void CombinationCore(char * str, int len, vector<char> &rs)
{
    if(len == 0)//相當於此時的組合串的長度滿足最開始的要求了,即m==0
    {
        vector<char>::iterator it;
        for(it = rs.begin(); it < rs.end(); it++)
            cout<<(*it);
        cout<<endl;
        return;
    }
    if(*str == '\0')//即n == 0
        return;
    rs.push_back(*str);
    //把當前字符當做組合的一部分
    CombinationCore(str + 1,len - 1,rs);
    rs.pop_back();//刪除當前字符,恢復之前的狀態
    //不把當前字符作為組合的一部分
    CombinationCore(str + 1, len,rs);
}
void getCombination(char* str)
{
    if(str == nullptr)
        return;
    int length = strlen(str);
    vector<char> rs;
    for(int i = 1; i <= length; i++)
        CombinationCore(str,i,rs);
}
int main()
{
    char s[] = "abcd";
    getCombination(s);
}

 結果如下:

此處有幾點需要注意的:

1.len表示組合串的長度,即m。

2.注意遞歸的終止條件:*str == '\0'和len == 0,對於前者相當於已經遍歷完整個字符串了,此時直接返回即可;對於后者,相當於找到符合的組合串,所以要處理結果(可以打印或存儲,本例是打印),然后返回執行尋找下一種長度的組合串。

3.由於要考慮兩種情況,先考慮第一種情況,把當前字符算入組合串中,然后需要從rs中刪除當前字符串(即恢復原狀),才考慮第二種情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM