[技巧] 全排列问题的五种解法

一、全排列

问题定义:给任意个元素,求解所有可能得排列方式

解法一
// 数比较少可以用暴力循环求解。
int main()
{
	int i,j,k;
	for(i=1;i<=3;i++){
		for(j=1;j<=3;j++){
			for(k=1;k<=3;k++){
				if(i!=j&&j!=k&&k!=i)
					printf("%d %d %d\n",i,j,k); 
			}
		}
	}
}
解法二
// DFS 搜索每个位置
int dfs(int level){
	if(level==n){//层数==最大深度时,递归终止 
		for(int i=0;i<n;i++)
			printf("%d ",result[i]);
		printf("\n");
		return 0;
	}
	for(int i=1;i<=n;i++){//深度优先遍历 
		if(!visited[i]){//该数字处于可访问状态 
			visited[i]=1;// 状态置为1,表示该数字变为不可访问状态 
			result[level]=i;
			dfs(level+1);//继续向下遍历 
			visited[i]=0;//恢复为可访问状态 
		}
	}
}
解法三
// 对解法二的改进,将可用元素交换到后面,节省visited数组的开销
int swap(int *x,int *y)
{
	int temp;
	temp=*x;
	*x=*y;
	*y=temp;
}
int dfs(int level,int a[],int m){
	if(level==m){//level==m时,递归终止 
		for(int i=0;i<=m;i++)
			printf("%d ",a[i]);
		printf("\n");
		return 0;
	}
	else{
		for(int j=level;j<=m;j++){
			swap(&a[j],&a[level]);//交换位置 
			dfs(level+1,a,m);
			swap(&a[j],&a[level]);//交换回来 
		}
	}
}
解法四

前三种解法,都不适合解决 存在重复元素 的情况,可以通过保证每个位置不重复使用相同元素的方式,防重复,解法如下:

func getCombine(candidates []int) [][]int {
	var ans [][]int
	var dfs func(acc []int, pos int)

	dfs = func(acc []int, pos int) {
		if pos == len(acc) {
			comb := make([]int, len(acc))
			copy(comb, acc)
			ans = append(ans, comb)
		}
		used := map[int]bool{} // 确保相同元素当前阶段只选一次
		for i := pos; i < len(acc); i++ {
			if !used[candidates[i]] {
				acc[pos] = candidates[i]
				used[candidates[i]] = true
				candidates[i], candidates[pos] = candidates[pos], candidates[i] // 将未使用的元素交换到后面
				dfs(acc, pos+1)
				candidates[i], candidates[pos] = candidates[pos], candidates[i] // 恢复状态
			}
		}
	}
	acc := make([]int, len(candidates))
	dfs(acc, 0)
	return ans
}
解法五

解法四在重复元素多,不同元素少的情况(如:11111222)效率较低,针对这种情况,我们可以将所有元素统计个数后,再进行dfs,次数每轮只需在不同元素中选择一个即可

func goodsOrder(goods string) []string {
	cnts := make([]int, 26)
	for i := 0; i < len(goods); i++ {
		cnts[goods[i]-'a']++
	}
	var ans []string
	var dfs func(acc []byte, pos int)
	dfs = func(acc []byte, pos int) {
		if pos == len(goods) {
			ans = append(ans, string(acc))
			return
		}
		for i := 0; i < 26; i++ {
			if cnts[i] > 0 {
				cnts[i]--
				acc[pos] = byte('a' + i)
				dfs(acc, pos+1)
				cnts[i]++
			}
		}
	}
	acc := make([]byte, len(goods))
	dfs(acc, 0)
	return ans
}

你可能感兴趣的:(算法)