《剑指Offer》读书笔记---面试题28:字符串的排列,(扩展:求字符串的所有组合)

题目:输入一个字符串,打印出字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。


书上的解法:

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>


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<cstdlib>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>


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<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>

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 ;
}


尚未解决的问题:

上述代码只有在输入的字符串的字符全不相同时才正确,否则的话会输出重复的组合。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值