题目要求:
输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则输出字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab、cba。
参考资料:剑指offer第28题。
题目分析:
1. 输出的字符串必须包含原字符串的所有字符,只是字符顺序换了;
2. 考虑有字符重复的情况;
3. 思路是:
1) 分别把第一个字符和后面的字符交换;
2) 固定第一个字符,求后面字符的排列;
3) 把第二个字符和后面的字符交换,然后固定.......
代码实现:
#include <iostream>
using namespace std;
void PrintAllPermutation(char *pStr);
int main(void)
{
char pStr[] = "aaab";
PrintAllPermutation(pStr);
return 0;
}
void PrintAllPermutation(char *pStr,char *pStart)
{
int flag = 0;
if(*pStart=='\0')
cout << pStr << endl;
else
{
for(char *pCh = pStart;*pCh != '\0';++pCh)
{
//有重复的就不交换,也不递归
for(char *p = pStart;p!=pCh;++p)
{
if(*p == *pCh)
{
flag = 1;
break;
}
}
if(flag)
{
flag = 0;
continue;
}
char tmp = *pCh;
*pCh = *pStart;
*pStart = tmp;
PrintAllPermutation(pStr,pStart+1);
tmp = *pCh;
*pCh = *pStart;
*pStart = tmp;
}
}
}
void PrintAllPermutation(char *pStr)
{
if(pStr==NULL)
return;
PrintAllPermutation(pStr,pStr);
}
扩展问题:
若是输出所有组合,又怎么求?
如输入abc,则所有组合为:a、b、c、ab、ac、bc、abc
问题分析:
1. 如果有相同字符,怎么办?可以把先输出的组合存储起来,当新的字符需要输出的时候与存储比较,如果有相同的就不输出
2. 可以用位运算来求:如果输入为3个字符,则位运算方法就为3位二进制(1~7),一次遍历1~7这七个数,输出数中为1对应的字符即可;
代码实现:
#include <iostream>
#include <string>
#include <set>
using namespace std;
set<string> store;
void SubSet(char *pStr);
int main(void)
{
char pStr[] = "aaabc";
SubSet(pStr);
return 0;
}
void Print(char *pStr,int n,int data)
{
char *p = new char[n];
int j = 0;
for(int i = 0;i<n;i++)
{
if(data&(1<<i))
p[j++] = pStr[i];
}
p[j] = '\0';
if(store.find(p) == store.end())
{
store.insert(p);
cout << p << endl;
}
delete []p;
}
void SubSet(char *pStr)
{
if(pStr==NULL)
return;
int len = strlen(pStr);
for(int i = 1;i<(1<<len);i++)
{
Print(pStr,len,i);
}
}