http://blog.csdn.net/hackbuteer1/article/details/7462447
一、字符串的排列
用C++写一个函数, 如 Foo(const char *str), 打印出 str 的全排列,
如 abc 的全排列: abc, acb, bca, dac, cab, cba
一、全排列的递归实现
为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。首先考虑213和321这二个数是如何得出的。显然这二个都是123中的1与后面两数交换得到的。然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。找到这个规律后,递归的代码就很容易写出来了:
- #include<iostream>
- using namespace std;
- #include<assert.h>
- void Permutation(char* pStr, char* pBegin)
- {
- assert(pStr && pBegin);
- if(*pBegin == '\0')
- printf("%s\n",pStr);
- else
- {
- for(char* pCh = pBegin; *pCh != '\0'; pCh++)
- {
- swap(*pBegin,*pCh);
- Permutation(pStr, pBegin+1);
- swap(*pBegin,*pCh);
- }
- }
- }
- int main(void)
- {
- char str[] = "abc";
- Permutation(str,str);
- return 0;
- }
另外一种写法:
- //k表示当前选取到第几个数,m表示共有多少个数
- void Permutation(char* pStr,int k,int m)
- {
- assert(pStr);
- if(k == m)
- {
- static int num = 1; //局部静态变量,用来统计全排列的个数
- printf("第%d个排列\t%s\n",num++,pStr);
- }
- else
- {
- for(int i = k; i <= m; i++)
- {
- swap(*(pStr+k),*(pStr+i));
- Permutation(pStr, k + 1 , m);
- swap(*(pStr+k),*(pStr+i));
- }
- }
- }
- int main(void)
- {
- char str[] = "abc";
- Permutation(str , 0 , strlen(str)-1);
- return 0;
- }
二、去掉重复的全排列的递归实现
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。下面给出完整代码:
- #include<iostream>
- using namespace std;
- #include<assert.h>
- //在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等
- bool IsSwap(char* pBegin , char* pEnd)
- {
- char *p;
- for(p = pBegin ; p < pEnd ; p++)
- {
- if(*p == *pEnd)
- return false;
- }
- return true;
- }
- void Permutation(char* pStr , char *pBegin)
- {
- assert(pStr);
- if(*pBegin == '\0')
- {
- static int num = 1; //局部静态变量,用来统计全排列的个数
- printf("第%d个排列\t%s\n",num++,pStr);
- }
- else
- {
- for(char *pCh = pBegin; *pCh != '\0'; pCh++) //第pBegin个数分别与它后面的数字交换就能得到新的排列
- {
- if(IsSwap(pBegin , pCh))
- {
- swap(*pBegin , *pCh);
- Permutation(pStr , pBegin + 1);
- swap(*pBegin , *pCh);
- }
- }
- }
- }
- int main(void)
- {
- char str[] = "baa";
- Permutation(str , str);
- return 0;
- }
二、字符串的组合(http://blog.csdn.net/hackbuteer1/article/details/7462447)
题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
上面我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:
#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); //将字符串一个一个的压入vector 这里是压入第一个字符
Combination(string + 1 , number - 1 , result); //第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;
//或者不要第一个字符
result.pop_back();
Combination(string + 1 , number , result); //第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。
}
int main(void)
{
char str[] = "abc";
Combination(str);
return 0;
}
方法二:用位运算来实现求组合
- #include<iostream>
- using namespace std;
- int a[] = {1,3,5,4,6};
- char str[] = "abcde";
- void print_subset(int n , int s)
- {
- printf("{");
- for(int i = 0 ; i < n ; ++i)
- {
- if( s&(1<<i) ) // 判断s的二进制中哪些位为1,即代表取某一位
- printf("%c ",str[i]); //或者a[i]
- }
- printf("}\n");
- }
- void subset(int n)
- {
- for(int i= 0 ; i < (1<<n) ; ++i)
- {
- print_subset(n,i);
- }
- }
- int main(void)
- {
- subset(5);
- return 0;