程序员面试100题之28字符串排列

// 程序员面试100题之28字符串排列.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <string>//string.h does not work
using namespace std;
/*
void permution(string &str)//函数中只是输出结果,所以不改变值
{
	// cout<<" str is "<<str<<endl; 这句能看出来程序思想错误,虽然确实每个分支都遍历了,但是根元素只进站出站一次,所以根元素只输出一次。递归本身的性质决定
	size_t len = str.length();
	if(len==0) 
	{
		cout<<endl;
		return;
	}
	string str2;//  = new string is a points
	for(size_t i=0;i<len;i++)
	{
		str2 = str;
		cout<<str[i];
		str.erase(i,1);
		permution(str);
		str = str2;// recovery
		
	}
}
*/
static int sum=0;
/*permution2 计算不同元素的排列方式,当所有元素的不同时计算排列(全排列),当有相同的元素时,过滤掉相同的元素,相当于这些元素的不同排列个数(不同于组合)*/
void permution2(string &str,int k)//这思想来自于答案,交换第一个元素和其余的一个元素,使得每次调用之后第一个元素都不在相同,即a bcd, b acd, c bad,d bca. 这样当a 入栈时,函数调用bcd,b入栈时,函数调用acd,
{
	 //cout<<" str is "<<str<<endl; 
	size_t len = str.length();
	if(k==len) 
	{
		for (int j=0;j<len;j++)
		{
			cout<<str[j];// 并没有删除和添加元素,而是在原来数组的基础上处理,所以才能把原来的值都取出来
		}
		cout<<endl;sum++;//str2="";
		return;
	}
	string str2="";//  = new string is a points,should be placed here, create in every 
	
	char ch_temp;
	for(size_t i=k;i<len;i++)
	{
		ch_temp = str[i];
		str[i] = str[k];
		str[k] = ch_temp;
		for (int i1=0;i1<str2.length();i1++)//here judge
		{
			if (str2[i1]==str[k])//already exist
			{
				ch_temp = str[i];//
				str[i] = str[k];
				str[k] = ch_temp;
				//if (k!=0)
				//{
				//	return;// here is wrong, when return 主函数只执行一次就被返回,主函数的for循环没执行
				//}
				//else
					goto label;//break;
			}
		}
		str2.push_back(str[k]);// 添加到str2 然后判断是否已经存在
		//? cout<<str[k];//这样输出还是不好使
		permution2(str,k+1);
		ch_temp = str[i];
		str[i] = str[k];
		str[k] = ch_temp;
		label:;//empty sentence
	}
}


上面是我的代码,下面是别人的代码,看到后自惭形愧呀!
bool IsSwap(char* pBegin , char* pEnd)  //在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等
{  
	char *p;  
	for(p = pBegin ; p < pEnd ; p++)  
	{  
		if(*p == *pEnd)  
			return false;  
	}  
	return true;  
}  
void Permutation(char* pStr , char *pBegin)  
{  
	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))  
			//if(i==0||pBegin != pCh)// the first exchanged even same, this is wrong
			{  
				swap(*pBegin , *pCh);  
				Permutation(pStr , pBegin + 1);  
				swap(*pBegin , *pCh);  
			}  
		}  
	}  
}
一直不是道自己有多笨,有多差,想了很久才看明白别人的代码。起始就是根据排列的定义,一个元素接一个元素的选择,对于有相同的元素,则当前位置的选择跳过已经选择过的元素,也就是上一步的IsWap()函数。假如当前的位置为pBegin,因为pBegin前的位置都已经选择好了,于是判断当前位置开始之后的所有元素pCh那些能够放在当前位置,如果能,则交换pCh和pBegin,然后判断下一个位置(即递归)。例如aabcc,当pBegin=0时,能选择的元素位置为0,2,3.只有三个序列后进入下一层递归,aabcc,baacc,cabac。进一步,假设aabcc序列进入下一层递归,pBegin=1,第一个位置为a固定了,此时第二个位置能选择的依然只有三个元素,生成的可以进入下一层递归的序列为abcc,bacc,cbac,注意不能有cbca序列进入下一层,因为当pCh指向第二个c时,已经选择过第一个c了,IsWap()函数不成立。以此类推。我不知道自己写了这么多乱码七糟的东西,只是感觉自己掉进了这个漩涡里,花了很久才出来。本博客只作为自己学习札记,若您浪费了时间读到此处,并对我的愚昧颇感吃惊,我将不胜荣幸!
void Combination(char *string ,int number,vector<char> &result);  

void Combination1(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);  // 对于重复元素,可以在进入容器之前,判断是够存在,若存在则不进入容器
	Combination(string + 1 , number - 1 , result);  
	result.pop_back();  
	Combination(string + 1 , number , result);  
}
组合

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值