问题定义:给任意个元素,求解所有可能得排列方式
// 数比较少可以用暴力循环求解。
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
}