您的位置:首页 > 其它

字符串的组合 位图和递归分别实现

2014-03-03 20:39 134 查看

方法一:利用位图方法求字符串的组合(类似于位运算模拟加法)

题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
 解析:我们可以通过位数组来实现打印所有组合,这类似于用字符串模拟加法操作一样。不过用字符串模拟加法操作是逢10进1,用位模拟是逢2进1。以abc为例:
初始化位bitset<3>   模拟每次加1它的变化为为  000---001
---010 -- 011 --- 100 ---101 --- 110 --111    。当某一位为 0的时候,不输出,为 1的时候输出对应于
abc中的那一位。
 源码如下:
[cpp] view
plaincopy

1.  #include <iostream>  
2.  #include <bitset>  
3.  #include <string>  
4.  using std::cout;  
5.  using std::cin;  
6.  using std::endl;  
7.  using std::string;  
8.  using std::bitset;  
9.    
10. // 由于c++中bitset不支持动态分配。 使用bitset<n>时 n的值不能使用局部变量  
11. // 所以现在只能是用全局变量计算出字符的个数,再赋值给n。 当STR改变时,不要  
12. // 忘了手动改变CHAR_COUNT 的值  
13. const string STR = "abc";   
14. const int CHAR_COUNT = 3; // 字符的个数  
15.   
16. bool Increment(bitset<CHAR_COUNT>&bits)  
17. {  
18.     if(CHAR_COUNT <= 0)  
19.         return false;  
20.     for(int i = CHAR_COUNT-1; i >=0; i--)  
21.     {  
22.         if(0 == bits[i])  
23.         {  
24.             bits[i] = 1;  
25.             break;  
26.         }  
27.         else   
28.         {  
29.             if(i != 0)   
30.             {  
31.                 bits[i] = 0; // 相当于进位操作,低位置为0  
32.             }  
33.             else  
34.             {  
35.                 return false; // 最高位为1 ,再次进行加法将溢出  
36.             }  
37.         }  
38.     }  
39.     return true;  
40. }  
41. void Print(const bitset<CHAR_COUNT>&bits, const string&str)  
42. {  
43.     if(CHAR_COUNT <= 0 || CHAR_COUNT != str.length())  
44.     {  
45.         return;  
46.     }  
47.     for(int i = 0; i != CHAR_COUNT; i++)  
48.     {  
49.         if(1 == bits[i])  
50.             cout << str[i];  
51.     }  
52.     cout << endl;  
53. }  
54.   
55. void Combination()  
56. {  
57.     bitset<CHAR_COUNT> bits;  
58.     while(Increment(bits))  
59.     {  
60.         Print(bits, STR);  
61.     }  
62. }  
63. int main()  
64. {  
65.     Combination();  
66.     system("pause");  
67. }  

方法二:递归

假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:

[cpp] view plaincopy

#include<iostream>  
#include<vector>  
#include<cstring>  
using namespace std;  
#include<assert.h>  
  
void Combination(char *string ,int number,vector<char> &result);  
  
void Combination(char *string)  
{  
    assert(string != NULL);  
    vector<char> result;  
    int i , length = strlen(string);  
    for(i = 1 ; i <= length ; ++i)  //打印字符串的长度
        Combination(string , i ,result);  
}  
  
void Combination(char *string ,int number , vector<char> &result)  
{  
    assert(string != NULL);  
    if(number == 0)  
    {  
        static int num = 1;  
        printf("第%d个组合\t",num++);  
  
        vector<char>::iterator iter = result.begin();  
        for( ; iter != result.end() ; ++iter)  
            printf("%c",*iter);  
        printf("\n");  
        return ;  
    }  
    if(*string == '\0')  
        return ;  
    result.push_back(*string);  
    Combination(string + 1 , number - 1 , result);  
    result.pop_back();  
    Combination(string + 1 , number , result);  
}  
  
int main(void)  
{  
    char str[] = "abc";  
    Combination(str);  
    return 0;  
}  

由于组合可以是1个字符的组合,2个字符的字符……一直到n个字符的组合,因此在函数void
Combination(char* string),我们需要一个for循环。另外,我们一个vector来存放选择放进组合里的字符。
另外一种递归实现如下:个人认为没有上面的递归容易理解

/*

解析:

算法分为4步骤

1. 从首字符到尾字符循环

2. 输出被循环到的字符i

3. 如果循环到的字符i后面还有字符i + 1,递归,以后面的字符i + 1为起点重复步骤(2)和(3)

4. 如果被循环的字符后面没有字符跳出循环

*/

#include <iostream>

#include <string.h>

#include <stdlib.h>

using namespace std;

char str[] = "hart";

char* out;

void Backtrack(char str[], char* out, int length, int curr, int start)

{

    for (int i = start; i < length; i++)

    {

        out[curr] = str[i];

        out[curr + 1] = '\0';

        cout << out << " ";

        if (i < length - 1)

        Backtrack(str, out, length, curr + 1, i + 1);

    }

    cout << endl;

}

int main()

{

    out = (char*) malloc(strlen(str) + 1);

    Backtrack(str, out, strlen(str), 0, 0);

    //cout << "Hello world!" << endl;

    return 0;

}

注:字符串的全排列的递归,非递归实现见http://blog.csdn.net/huazhongkejidaxuezpp/article/details/19237439
扩展题:组合问题(从M个不同字符中任取N个字符的所有组合)

运用方法二的递归算法解决。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: