`

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

J# 
阅读更多
题目如下:用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数组,标识第几个元素可用(即还没被用来排列)
这一种的解题思路来源于图遍历的深度遍历(搜索),关于深度遍历的详细可以参考http://zhidao.baidu.com/question/17057725.html



参考代码如下:
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;
	}
}




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

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

相关推荐

Global site tag (gtag.js) - Google Analytics