递归:全排列问题

全排列问题

给出1~n,n个整数,把这n个整数按照这种顺序输出n个数的所有排列:

  • 按照字典序从小到大顺序输出,如果说(a1,a2,……an)的字典序小于(b1,b2,……bn),指的是存在一个i,使得a1=b1,a2=b2,……a(i-1)=b(i-1),ai<bi
  • 例如:1,2,3三个数按顺序输出全排列就是(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1)

解析

以输入的是1,2,3为例,这个问题可以分解成这样的几个小问题:
在这里插入图片描述
拿出其中一个问题,以1开头的三位全排列内部可以分成三个小问题,这三个小问题其实就是在1为开头的基础上,判断第二位后面的各个位
因为1已经在第一位出现过了,所以就不会出现在第二位,那么第二位只有两小小个问题
在这里插入图片描述
如此递推下去,这就是这道题的解决思想

那么我们可以设置一个boolean类型的HashTable,用来记录到目前为止,前几位哪些数字已经使用了,已经使用的记为true
设置一个index,指示当前是第几位
假设我们在第一位为2,第二位为1的基础上到了第三位,第三位只能是三3,到了这一步,这一种情况已经走到底了,hashTable都为true
在这里插入图片描述
之后返回到第二位,第一位的2我们不能动,第二位还可以是3,但是由于刚才我们在第三位用到了3hashTable[3]已经是true了,第二位无法变成3,这就说明,我们在返回到上这一位之后,要把子问题中变成true的变回false
在这里插入图片描述

代码实现

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main{
	
	// 参与全排列的数字为1~n,同时也是位数
	static int n;
	
	// hashTable表示 数字i 在前几位中是否已经用过了
	// 0位空着不用,这样更方便理解
	static boolean[] hashTable = new boolean[n+1];
	
	// 存放当前排列的结果,从i=1开始,0位空着不用,这样更方便理解
	static int[] P = new int[n+1];
	
	// index表示当前处理的是哪一位
	public static void generateP(int index) {
		// 如果当前位数是第n位(index是从1开始的),说明已经排完了
		if(index == n+1) { 
			// 输出整个排列
			for(int i=1; i<n; i++) {
				System.out.print(P[i]);
			}
			System.out.println();
		}
		
		// 对于1~n的每一个数,都尝试放在第index位(当前位)上
		for(int i=1; i<=n; i++) {
			if(hashTable[i] == false) { // 数字i在前几位中没有出现过
				//i设为全排列的第index位
				P[index] = i; 
				// 把i标记成已经用过了
				hashTable[i] = true; 
				// 处理子问题(下一位往后
				generateP(index + 1); 
				// 处理完子问题,把i标记还原,以保证当前位位可以使用
				hashTable[i] = false; 
			}
		}
	}
	
	public static void main(String[] args) throws IOException{
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		// 参与全排列的数字为1~n,同时也是位数
		n = Integer.parseInt(bf.readLine());
		
		// 从第一位开始
		generateP(1);
	}
}


参考:胡凡《算法笔记》
发布了52 篇原创文章 · 获赞 9 · 访问量 6239

猜你喜欢

转载自blog.csdn.net/weixin_43553694/article/details/104223331