题目:输入一个字符串,打印出字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
书上的解法:
#include
#include
#include
#include
#include
void Permutation( char *pStr ) ;
void Permutation( char *pStr, char *pBegin ) ;
void Permutation( char *pStr )
{
if( NULL == pStr )
{
return ;
}
Permutation( pStr , pStr) ;
}
void Permutation( char *pStr, char *pBegin )
{
if( '\0' == *pBegin )
{
printf("%s\n",pStr) ;
}
else
{
for(char *pCh = pBegin ; *pCh != '\0' ; ++pCh)
{
char temp = *pCh ;
*pCh = *pBegin ;
*pBegin = temp ;
Permutation( pStr, pBegin + 1 ) ;
temp = *pCh ;
*pCh = *pBegin ;
*pBegin = temp ;
}
}
}
int main(void)
{
freopen("in.txt","r",stdin) ;
char szStr[100] ;
while(scanf("%s",szStr) != EOF)
{
Permutation(szStr) ;
printf("\n") ;
}
return 0 ;
}
书上的解法,虽然可以打印出字符串的全排列,但是那些排列不是按字典序打印出来的,所以我用我以前经常用的类似位图的方法打印字典序的全排列。
#include
#include
#include
#include
#include
const int N = 100 ;
bool isUse[N] ;
void MyPermutation(const char *pszStr ) ;
void MyPermutation(const char *pszStr ,int nIndex ,int nLen ,char *pszStore) ;
void MyPermutation(const char *pszStr )
{
if( NULL == pszStr)
{
return ;
}
int nLen = strlen(pszStr) ;
char *pszStore = new char [ nLen + 1 ] ;
MyPermutation( pszStr,0,nLen,pszStore ) ;
delete [] pszStore ;
}
void MyPermutation( const char *pszStr , int nIndex ,int nLen ,char *pszStore )
{
if( nIndex >= nLen )
{
pszStore[nIndex] = '\0' ;
printf("%s\n",pszStore) ;
}
else
{
for(int i = 0 ; i < nLen ; ++i)
{
if(false == isUse[i])
{
isUse[i] = true ;
pszStore[nIndex] = pszStr[i] ;
MyPermutation(pszStr,nIndex+1,nLen,pszStore) ;
isUse[i] = false ;
}
}
}
}
int main(void)
{
freopen("in.txt","r",stdin) ;
char szStr[100] ;
while(scanf("%s",szStr) != EOF)
{
MyPermutation(szStr) ;
printf("\n") ;
}
return 0 ;
}
本题扩展:
求n个字符,长度为m的所有组合。
书上提供的思路(不太怎么实现):
在求n个字符的长度为m(1 < m < n)的组合的时候,我们把这n个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取m-1个字符;如果组合里不包含第一个字符,则下一步在剩余的n-1个字符里选取m个字符。也就是说,我们可以把求n个字符组成长度为m的组合的问题分解成两个子问题,分别求n-1个字符串中长度为m-1的组合,以及求n-1个字符的长度为m的组合。这两个子问题都 可以用递归的方式解决。
我的大概思路:
求n个字符,长度为m的所有组合。每一次递归从剩余的字符中正向选取一个字符,在递归返回后,再正向选取下一个字符,这样可以保证不会重复选择。
#include
#include
#include
#include
using std::endl ;
using std::cout ;
const int N = 100 ;
void PrintCombination( char *pszStr ,int nCombinLen ) ;
void PrintCombination( char *pszStr,int nStrLen ,char *pszCombination,int nNowLen , int nCombinLen ,int nBeginPos) ;
void PrintCombination( char *pszStr,int nCombinLen )
{
if( NULL == pszStr )
{
return ;
}
int nLen = strlen(pszStr) ;
char *szStore = new char[ nLen+1 ] ;
for(int i = 1 ; i <= nCombinLen ; ++i )
{
PrintCombination(pszStr,nLen,szStore,0,i,0) ;
}
}
void PrintCombination( char *pszStr,int nStrLen,char *pszCombination,int nNowLen,int nCombinLen ,int nBeginPos )
{
if( nNowLen >= nCombinLen )
{
pszCombination[nNowLen] = '\0' ;
printf( "%s\n",pszCombination ) ;
}
else
{
for(int i = nBeginPos ; i < nStrLen ; ++i)
{
pszCombination[nNowLen] = pszStr[i] ;
PrintCombination( pszStr,nStrLen,pszCombination,nNowLen+1,nCombinLen,i+1) ;
}
}
}
int main(void)
{
freopen("in.txt","r",stdin) ;
char szStr[N] ;
int m ;
while(scanf("%s %d",szStr,&m) != EOF)
{
PrintCombination(szStr,m) ;
printf("\n") ;
}
return 0 ;
}
上述代码只有在输入的字符串的字符全不相同时才正确,否则的话会输出重复的组合。