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

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

题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有abcabacbcabc

 解析:我们可以通过位数组来实现打印所有组合,这类似于用字符串模拟加法操作一样。不过用字符串模拟加法操作是逢101,用位模拟是逢21abc为例:

初始化位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// 最高位为,再次进行加法将溢出  

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

  1. #include<iostream>  
  2. #include<vector>  
  3. #include<cstring>  
  4. using namespace std;  
  5. #include<assert.h>  
  6.   
  7. void Combination(char *string ,int number,vector<char> &result);  
  8.   
  9. void Combination(char *string)  
  10. {  
  11.     assert(string != NULL);  
  12.     vector<char> result;  
  13.     int i , length = strlen(string);  
  14.     for(i = 1 ; i <= length ; ++i)  //打印字符串的长度
  15.         Combination(string , i ,result);  
  16. }  
  17.   
  18. void Combination(char *string ,int number , vector<char> &result)  
  19. {  
  20.     assert(string != NULL);  
  21.     if(number == 0)  
  22.     {  
  23.         static int num = 1;  
  24.         printf("第%d个组合\t",num++);  
  25.   
  26.         vector<char>::iterator iter = result.begin();  
  27.         for( ; iter != result.end() ; ++iter)  
  28.             printf("%c",*iter);  
  29.         printf("\n");  
  30.         return ;  
  31.     }  
  32.     if(*string == '\0')  
  33.         return ;  
  34.     result.push_back(*string);  
  35.     Combination(string + 1 , number - 1 , result);  
  36.     result.pop_back();  
  37.     Combination(string + 1 , number , result);  
  38. }  
  39.   
  40. int main(void)  
  41. {  
  42.     char str[] = "abc";  
  43.     Combination(str);  
  44.     return 0;  
  45. }  

由于组合可以是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个字符的所有组合)

运用方法二的递归算法解决。





你可能感兴趣的:(字符串的组合 位图和递归分别实现)