(1)字符串全排列 / 组合

题目描述:输入一个字符串,打印出该字符串的全部排列;

例如:字符串:abc     全排列:(abc , acb) , (bac , bca) , (cba , cab);

解题思路:

递归实现:从字符串中“依次”选择一个字符作为“首字符”,并在该“首字符”前提下,对剩余字符进行递归全排列处理;


“依次”:即始终在“初始字符串”的前提下,后面的字符分别于第一个字符交换;

字符串abc:

(abc)首字符a-->求剩余bc全排列:abc , acb;-->(a,b)交换-->bac;

(bac)首字符b-->求剩余ac全排列:bac , bca;-->(a,b)交换-->abc(以便在此基础上得到cba)-->(a,c)交换-->cba;

(cba)首字符c-->求剩余ba全排列:cba,cab;


算法递归实现:

#include<iostream>
using namespace std;
//------------------------------------------------------------------------------------------------------------------
void  Permutation(char* pStr , char* pBegin);
void  Swap(char *ch1 , char *ch2);
//-------------------------------------------------------------------------------------------------------------------
void  Swap(char *ch1 , char *ch2)
{
	char temp = *ch1;
	*ch1 = *ch2;
	*ch2 = temp;
}

//不能保证出现重复排列。
void Permutation(char* pStr , char* pBegin)
{
	if(*pBegin == '\0')
	{
		printf("%s\n" , pStr);
	}
	else
		for(char* pch = pBegin; *pch != '\0'; ++pch)
		{
                        Swap(pch , pBegin); 
			Permutation(pStr , pBegin + 1);
			Swap(pch , pBegin);
		}
}

void Permutation(char* pStr)
{
	if(pStr == NULL)
		return ;

	Permutation(pStr , pStr);
}

但是若字符串中出现重复的字符,两者交换。全排列中会出现重复的结果。这样不仅加大工作量,而且还是没有意义的,故应该去掉重复的全排列结果。

怎么去除呢?

规则:从首字符起,每个字符依次与后面不重复的字符交换。

例子:字符串abb;

(abb)首字符a-->求剩余全排列:abb-->(b,b)相等不交换;-->(a,b)交换bab;

(bab)首字符b-->求剩余全排列:bab , bba;-->(b,a)交换abb-->由于二三字符b ,b 相同,故a不再与第三个字符交换,结束;

代码实现:

#include<iostream>  
using namespace std;  
//------------------------------------------------------------------------------------------------------------------------
bool IsSwap(char* pBegin , char* pEnd);           //判断是否有字符相等
void Permutation(char* pStr , char *pBegin);
//------------------------------------------------------------------------------------------------------------------------
void Permutation(char* pStr)
{
	if(!pStr)
		return;

	Permutation(pStr , pStr);
}
  
//在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等  
bool IsSwaped(char* pBegin , char* pEnd)  
{  
    char *S;  
    for(S = pBegin ; S < pEnd ; S++)  
    {  
        if(*S == *pEnd)  
            return false;  
    }  
    return true;  
}  

void Permutation(char* pStr , char *pBegin)  
{  
  
    if(*pBegin == '\0')  
    {  
        printf("%s\n",pStr);  
    }  
    else  
    {  
	  //依次与首字符交换,固定。剩余递归进行全排列
        for(char *pCh = pBegin; *pCh != '\0'; pCh++)  
        {  
            if(IsSwaped(pBegin , pCh))  
            {  
                swap(*pBegin , *pCh);  
                Permutation(pStr , pBegin + 1);  
                swap(*pBegin , *pCh);  
            }  
        }  
    }  
}  


字符串的组合问题:

问题描述:给定一个字符串,求该字符串中所有字符的组合;例如abc,所求组合为:a , b , c , ab , ac , bc , abc;


长度为n的字符串,选取m个字符的组合,其中1 <= m <= n;

设总组合数为Comb(n , m) = Comb(n , 1) + Comb(n , 2) + Comb(n , 3) + ......+ Comb(n , n);

递归求解

从首字符开始扫描,若被选中,则递归求解:Comb(n - 1 , m - 1);

                                 若未被选中,则递归求解:Comb(n - 1 , m);

递归终止条件: n = 0  或者  m = 0;


代码实现:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
//------------------------------------------------------------------------------------------------------------------
void Combination(char* pStr , int m , vector<char>& result);
//-------------------------------------------------------------------------------------------------------------------
//函数功能:求一个字符串的所有组合
//参数:字符串pStr
void Combination(char* pStr)
{
	if(pStr == NULL)
		return;

	vector<char> result;
      int length = strlen(pStr);

	for(int i = 1; i <= length; i++)
		Combination(pStr , i , result);
}

//函数功能:从一个字符串中选取m个字符
//参数:字符串pStr ,选取元素个数m , 存放结果result
void Combination(char* pStr , int m , vector<char>& result)
{
	if(pStr == NULL || (*pStr == '\0' && m != 0))
		return;

	//递归终止条件
	if(m == 0)
	{
		vector<char>::iterator  iter = result.begin();
		for( ; iter != result.end(); iter++)
			cout<<*iter<<' ';
		cout<<endl;

		return;     //注意
	}

	//选中此元素
	result.push_back(*pStr);
	Combination(pStr + 1 , m - 1 , result);
	result.pop_back();

	//未选中此元素
	Combination(pStr + 1 , m , result);

}

//----------------------------------------------------------------------------------------------------------------
int main()
{
	char string1 [] = " ";
      Combination(string1);

	char string2[] = "accd";
	Combination(string2);

	return 0 ;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值