全排列—含重复元素

本文介绍了全排列的概念,特别是处理含有重复元素时的全排列问题。文章通过三种不同的算法实现全排列:交换法、抽取法和使用`next_permutation`函数。交换法和抽取法在排列过程中进行了去重处理,确保不重复的全排列输出。`next_permutation`函数则直接利用STL库进行排列。所有代码示例均以C++编写,并提供了运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、初识全排列

在对n个元素且含有重复进行全排列时,其全排列的种类数量不在是n!种,因为含有重复元素,故对其进行全排列中含有重复的全排列类型。故在处理含有重复元素的问题时,需要对这些重复的元素进行相应的处理,即在进行全排列中需要对相应的重复元素进行去重。

二、相应的算法

1.交换法

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int number=0;
void f(int p,string str,int n){
	if(p==n){
		cout<<str<<endl;
		number++;
		return;
	}
	sort(str.begin()+p,str.end()); //使字符串按照升序进行排列 
	for(int i=p;i<n;i++){
		if(i>p&&str[i]==str[i-1]){ //未进行相关交换前进行去重,在此去重时原始的字符串必须是有序的。 
			continue;
		}
		swap(str[i],str[p]);
		f(p+1,str,n);
		swap(str[i],str[p]);
	}
}
int main(){
	string str="aabb";
	f(0,str,str.length());
	cout<<number<<endl;
	return 0;
} 

2.抽取法

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int number=0;
int vis[15]={0}; //表示未被访问过
void f(string a,int n,char b[],int p){
	if(p==n){
		cout<<b<<endl;
		number++;
		return;
	}
	//在对字符串进行有序排列中,也可以开始就对他进行有序排列,因为在每次进行追加中其vis[i]均会被置为0,回到其初始状态 
	for(int i=0;i<n;i++){
//		sort(a.begin()+i,a.end());
		if(i>0&&a[i]==a[i-1]&&!vis[i-1]){//进行去重,在去重需要是原来的字符串有序,同时保证a[i-1]未被访问过 
			continue;
		}
		if(!vis[i]){
			b[p]=a[i];
			vis[i]=1;
			f(a,n,b,p+1);
			vis[i]=0;
		}
	}
}
int main(){
	string str="baba";
	sort(str.begin(),str.end()); //对字符串进行有序排列 
	char b[15]="";
	f(str,str.length(),b,0);
	cout<<number<<endl;
	return 0;
} 

3.使用next_permutataion进行全排列

代码如下(示例):

#include <bits/stdc++.h>
using namespace std;
int main(){
	string str="baba";
	sort(str.begin(),str.end());
	int number=0;
	do{
		cout<<str<<endl;
		number++;
	}while(next_permutation(str.begin(),str.end()));
	cout<<number<<endl;
	return 0;
} 
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值