用深度遍历解决全排列问题

题目如下:用1,2,2,3,4,5这6个数字,用Java写一个main函数,打印出所有不同的排列,如:123254,522134等,要求:“3”与“5”不能相邻,“4”不能排在第3位。(看完题目先不要急着看答案,自己尝试做一下,或者你的做法更好^_^)


解题方案是把相邻问题抽象成一个2维数组,用0与1组成,如[0,1]或者[1,0]就表示0与1相邻的时候,如下图:
0 1 1 1 1 1
1 0 1 1 1 1
1 1 0 1 1 1
1 1 1 0 1 1
1 1 1 1 0 1
1 1 1 1 1 0
解释:0表示不能相邻,1表示可以相邻(当然你掉转也可以) [1,1],[2,2]...[6,6]这些当然为0了,自己与自己又怎可能相邻=。=
另外还需要设计一个boolean数组,标识第几个元素可用(即还没被用来排列)
这一种的解题思路来源于图遍历的深度遍历(搜索),关于深度遍历的详细可以参考[url]http://zhidao.baidu.com/question/17057725.html[/url]


参考代码如下:
import java.util.*;

public class DepthSearch {

//要排列的字符串数组
private String[] b = {"1","2","2","3","4","5"};

int n = b.length;

private String result ="";

//判断数组中哪个元素还可用与排列的标志位
private boolean[] visit = new boolean[n];

//用于标识相邻元素相通与否的2维数组
private int[][] a = new int[n][n];

//用于存放的排列结果的集合
private Set<String> set = new TreeSet<String>();

//计算有多少个元素被加入到TreeSet里面
private int count;


//执行main函数
public static void main(String[] args) {
new DepthSearch().start();

}


private void start(){
//初始化2维数组,1表示相连,0表示不通
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j){
a[i][j]=0;
}
else{
a[i][j]=1;
}
}
}

//加入不能相邻元素的限制条件,把2维数组对应该元素设置为0,这里是3与5不能相邻(对应第4个元素和第6个元素)
a[3][5]=0;
a[5][3]=0;

//表示以第1到第6个元素为第1位的情况进行排列(循环6次)
for(int i=0;i<n;i++){
this.sort(i);
}

System.out.println("set中元素为"+set.size()+"个");
System.out.println("TreeSet所过滤掉的元素共有:"+(count-set.size())+"个");
System.out.println("所有排列如下:");
for(String s:set){
System.out.print(s+" , ");
}
}

private void sort(int startIndex){
//被拿了出来的元素设置标志为true,表示不可用,false为可用
result = result + b[startIndex];
visit[startIndex] = true;

//当长度等于6的时候,即满足一种排列组合,加到TreeSet里面
if(result.length()==6){
//用if判断:4不能放在第3位
if(result.indexOf("4")!=2){
set.add(result);
count++;
}
}

//2维数组a[][]表示当前元素与相邻元素,若为1,即表示可以相邻,false表示下一个元素可用
for(int i=0;i<n;i++){
if(a[startIndex][i]==1 && visit[i]==false){
sort(i);

}
}

//若不符合跳出循环,即result减去一个再进行排列,直到跳出最外循环为止
result = result.substring(0,result.length()-1);
visit[startIndex] = false;
}
}



[color=red]有2个地方需要注意:[/color]
1)其实sort方法是6层for嵌套,当走到第6个for循环,所有条件都不满足的时候,就会先走最后两步[color=green]result = result.substring(0,result.length()-1);
visit[startIndex] = false;[/color] 减去一个字符并把那个字符设为可用,然后返回到第5层for循环,如果跑完也不满足要求就会再减一个返回第4层的for循环,以此类推。当把以第一个元素为第1位的所有排列组合计算出来并加到TreeSet里面之后,就会进行以第2个元素为第一位的所有排列组合的计算,一直到最后一位。

2)因为字符串“122345”出现两个2,所以排列会有重复,需要放到Set里面过滤一下,用HashSet也可以,而且更快,TreeSet打印出来的时候按从小到大的顺序好看一点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值