`

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

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打印出来的时候按从小到大的顺序好看一点。
分享到:
评论

相关推荐

    C#深度优先遍历实现全排列

    C#深度优先遍历实现全排列 C#深度优先遍历实现全排列是...在实际应用中,C#深度优先遍历实现全排列可以用来解决许多问题,例如,排列问题、组合问题等。同时,它也可以用来解决一些实际问题,例如,排列人员、物品等。

    python练习fibonacci全排列

    在Python中,可以使用内置的`itertools`模块来简化全排列问题的解决,`itertools.permutations()`函数可以直接生成一个可迭代对象,包含了输入序列的所有排列。 总结起来,"python练习fibonacci全排列"这个主题涵盖...

    全排列(多种算法实现)

    在全排列问题中,我们可以用回溯法配合DFS来实现。基本步骤如下: - 从序列的第一个元素开始,将其标记为已使用。 - 对序列中剩余的元素,依次与第一个元素进行排列,并递归地进行全排列。 - 当所有元素都尝试过...

    递推与递归DFS深度优先遍历

    **DFS(Depth-First Search,深度优先搜索)**作为一种经典的图遍历算法,广泛应用于各种问题中,包括但不限于迷宫问题、迷宫寻路、连通性检测等。 #### 递归DFS深度优先遍历的核心原理 在深入探讨具体的实例之前...

    FullPermutation_java_算法_全排列_

    本篇将详细介绍两种常用的Java方法来解决全排列问题,并探讨相关知识点。 ### 1. 递归法 递归法是一种自上而下解决问题的方法,它通过调用自身来解决子问题。在全排列问题中,我们可以从最简单的情况(只有一个...

    java递归实现N个数全排列输出

    在编程领域,全排列是一个经典的算法问题,它涉及到数组或字符串的所有可能的顺序组合。当给定一个包含N个不同元素的集合时,全排列就是要列出所有可能的N!(N的阶乘)种排列方式。在这个场景中,我们将探讨如何使用...

    寒假40.全排列2_全排列_40_

    在本例中,我们将深入探讨如何使用深度优先搜索(DFS)解决全排列问题。 深度优先搜索是一种用于遍历或搜索树或图的算法。在全排列问题中,我们可以将每一步选择一个未使用的数字看作是一个节点,而所有可能的选择...

    全排列-非递归算法

    全排列是一种经典的算法问题,它涉及在给定的有限序列中找出所有可能的元素排列方式。在本例中,我们关注的是非递归算法来实现全排列,这通常使用回溯法或者迭代的方式来完成,特别是在有新元素动态加入时,需要能够...

    关于全排列算法

    全排列算法是计算机科学中的一种经典算法,主要应用于解决如何生成一个给定集合的所有可能排列的问题。在给定的题目中,作者通过一个简单的递归方法实现了全排列的计算。以下是对该算法的详细解析: 首先,我们来看...

    quanpailie.rar_全排列

    递归是最直观的解决全排列问题的方法。我们首先选择第一个位置的元素,然后对剩下的元素进行全排列。这个过程可以表示为递归函数,如下: - 基本情况:当需要排列的元素只有一个时,只有一个排列(自身)。 - ...

    C++n个数全排列的算法

    在C++中实现全排列可以使用回溯法,这是一种在尝试解决问题时,当发现当前选择无法导致有效解时,会退回一步并尝试其他选择的方法。以下是一个简单的C++代码实现全排列的示例: ```cpp #include #include using ...

    N个数全排列的非递归算法

    在描述中提到了一个博客链接,虽然具体内容没有给出,但通常博主会详细解释如何用非递归的方式解决全排列问题。非递归算法通常采用迭代或回溯的方式来完成,这种方式相对于递归可能会更节省内存,因为递归深度过大...

    python实现全排列代码(回溯、深度优先搜索)

    通过上述两种方法,我们可以有效地解决全排列问题,理解回溯法和DFS的思想对于解决类似问题具有重要的指导意义。在实际编程中,根据问题的特点选择合适的方法,能够提高算法的效率和代码的可读性。

    全排列算法 全排列算法 (c#版)

    这种算法通常使用栈或递归来实现,递归版本易于理解,而迭代版本则更高效,避免了深度递归可能导致的堆栈溢出问题。 在C#中,我们可以创建一个递归函数来实现全排列。以下是一个简单的C#代码示例: ```csharp ...

    PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能

    实现全排列的方法有很多,本文主要介绍使用PHP语言实现基于图的深度优先遍历(DFS,Depth-First Search)算法来生成1到n的全排列。 深度优先遍历是一种用于遍历或搜索树或图的算法。这里所指的图是抽象意义上的,而...

    生成字符串的全排列,可以用回溯法实现

    总结来说,生成字符串全排列的问题可以通过回溯法有效地解决。这种方法的关键在于递归地尝试所有可能的选择,并在无法继续时及时回溯,避免无效的工作。回溯法不仅可以应用于字符串排列,还可以解决许多其他组合优化...

    递归实现全排列

    全排列问题可以通过递归来优雅地解决。具体策略如下: 1. **基本情况**:当数组中只有一个元素时,其全排列就是该元素本身,这是一次简单的返回。 2. **递归步骤**:对于长度为n的数组,我们可以选择数组中的任一...

    javascript-leetcode面试题解递归与回溯问题之第46题全排列-题解.zip

    解决这个问题的关键在于设计一个递归函数,它能够遍历所有可能的排列。以下是一个可能的解法: ```javascript function permute(nums) { let result = []; function backtrack(first = 0) { if (first === nums....

    c++-c++编程基础之leetcode题解第46题全排列.zip

    总结一下,本资源包主要涵盖了C++编程语言中的算法知识,特别是如何使用回溯法解决全排列问题。通过学习和实践这个题目的解法,开发者可以深化对C++编程的理解,提高解决实际问题的能力,同时为准备LeetCode等算法...

Global site tag (gtag.js) - Google Analytics