字符串的组合
题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
分析:在本系列博客的第28题《字符串的排列》中,我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。
假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;而是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:
1 void Combination(char* str) 2 { 3 if(str == NULL) 4 return; 5 6 int length = strlen(str); 7 vector<char> result; 8 for(int i = 1; i <= length; ++ i) 9 { 10 Combination(str, i, result); 11 } 12 } 13 14 void Combination(char* str, int number, vector<char>& result) 15 { 16 if(number == 0) 17 { 18 vector<char>::iterator iter = result.begin(); 19 for(; iter < result.end(); ++ iter) 20 printf("%c", *iter); 21 printf("\n"); 22 23 return; 24 } 25 26 if(*str == '\0') 27 return; 28 29 result.push_back(*str); 30 Combination(str + 1, number - 1, result); 31 result.pop_back(); 32 33 Combination(str + 1, number, result); 34 }
由于组合可以是1个字符的组合,2个字符的字符……一直到n个字符的组合,因此在函数void Combination(char* string),我们需要一个for循环。另外,我们一个vector来存放选择放进组合里的字符。
以上来自何海涛博客
其中,Combination函数里面可以再加一个条件,限制无效的后续步骤,如下面8-11行所示
1 void Combination(char *str, int number, vector<char>& result) 2 { 3 ...... 4 5 if(*str == '\0') 6 return; 7 8 if (number>strlen(str)) 9 { 10 return; 11 } 12 13 ...... 14 }
另外,根据该博客后面的跟帖回复,整理了一些其他算法。
1.用一个数组,模拟2进制加法器,某一个为1,则取对应的字符,若为0则不取,就能够实现字符组合。也可以不用数组。设有n个字符。
int num 从 1 自增到 2^n -1, 将num右移i位,跟1做按位&操作,即可判断第i个字符取还是不取。
1 void Combination1(char *str, int number) 2 { 3 if (number==0) 4 { 5 return; 6 } 7 8 while(number && *str!='\0') 9 { 10 if (number&1) 11 { 12 cout<<*str; 13 } 14 str++; 15 number >>= 1; 16 } 17 18 cout << endl; 19 } 20 void OutputCombination1(char *str) 21 { 22 if (str==NULL) 23 { 24 return; 25 } 26 27 int len = strlen(str); 28 int kinds = (1<<len)-1; 29 for(int i=1;i<=kinds;i++) 30 { 31 Combination1(str,i); 32 } 33 }
2.下面的代码也可以避免无效递归
1 void Combination2(char* str, vector<char>& result) 2 { 3 if(*str == '\0') 4 { 5 vector<char>::iterator iter = result.begin(); 6 for(; iter < result.end(); ++ iter) 7 printf("%c", *iter); 8 printf("\n"); 9 return; 10 } 11 result.push_back(*str); 12 Combination2(str + 1, result); 13 result.pop_back(); 14 Combination2(str+1, result); 15 } 16 17 void OutputCombination2(char *str) 18 { 19 if (str==NULL) 20 { 21 return; 22 } 23 24 vector<char> result; 25 26 Combination2(str,result); 27 }