字符串的组合 位图和递归分别实现
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个字符的所有组合)
运用方法二的递归算法解决。
相关文章推荐
- 剑指Offer28字符串的排列(递归和非递归实现)扩展有重复元素的排列,字符串的组合种类
- 字符串全排列与全组合的递归实现-Java版
- 字符串的全组合非递归实现
- 字符串的组合问题 递归和非递归实现
- 打印给定一字符串的所有字母组合——递归实现
- 字符串数组元素排列与组合的Java递归实现
- 组合函数递归和非递归实现
- 用递归的方法实现字符串的反序输出
- 递归实现全排列和组合
- 用非递归方法实现 求解字符串组合的问题 JAVA代码
- 迈瑞笔试题,递归实现字符串逆置
- asp 实现检测字符串是否为纯字母和数字组合的函数
- 用递归实现字符串的逆置
- 列出数组中取出的数的全部组合(用递归实现)
- 排列组合算法的递归实现
- 输入一串不重复的字符串,列出所有可能的组合(java实现)
- 二叉搜索树(递归和非递归分别实现)
- [算法] 输出 字符串的全部子组合 [dfs - 递归神技]
- 编写查找一个单链表特定元素的程序。分别使用递归和非递归方法实现,并比较它们的运行时间。
- 递归三兄弟——数的乘方、背包问题、组合的Java实现