全排列与康拓逆展开

(算法)全排列的递归算法Java实现过程

一、无重复项的全排列

全排列的数学定义就不再过多解释,考虑递归算法的实现可从下面几点入手(以数组为例,如对其他元素排列,将元素编号放入数组即可):

1、一个数的全排列,如排列{1},就是这个数本身这一种情况

2、两个数的全排列,如排列{1,2}:

 第一步:将{1}放在第零个位置,剩下的{2}进行一个数的全排列,结果为{1,2}

 第二步:将{2}放在第零个位置,剩下的{1}进行一个数的全排列,结果为{2,1}

 即两个数的全排列为以上2种情况。

3、三个数的全排列,如排列{1,2,3}:

 第一步:将{1}放在第零个位置,剩下的{2,3}进行两个数的全排列,结果为{1,2,3}  {1,3,2}

 第二步:将{2}放在第零个位置,剩下的{1,3}进行两个数的全排列,结果为{2,1,3}  {2,3,1}

 第三步:将{3}放在第零个位置,剩下的{1,2}进行两个数的全排列,结果为{3,1,2}  {3,2,1}

 即三个数的全排列为以上6种情况。

4、即m个数(无重)的全排列,就是将m个数分别放在第零个位置,再将剩下的m-1个数的全排列加在后面,当m-1=1时为递归的出口。
 

例题:

代码实习:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

public class Main2 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		char buf[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
		Set<String> lists = new TreeSet<>();
		perm(buf, 0, buf.length - 1, lists, n);
			
	}
	
	public static void perm(char[] buf, int start, int end, Set<String> lists, int a) {
	
		if (start == end) {// 当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可(特殊情况)
			StringBuilder strs = new StringBuilder("");
			for (int i = 0; i < buf.length; i++) {
				strs.append(buf[i]);
			}
			lists.add(strs.toString());
			if (lists.size() == a) {
				Object[] arr = lists.toArray();
				System.out.println(arr[arr.length - 1]);
				return ;
			}
		} else {// 多个字母全排列(普遍情况)
			ff: for (int i = start; i <= end; i++) {// (让指针start分别指向每一个数)
				char temp = buf[start];// 交换数组第一个元素与后续的元素
				buf[start] = buf[i];
				buf[i] = temp;
				perm(buf, start + 1, end, lists, a);// 后续元素递归全排列
				temp = buf[start];// 将交换后的数组还原
				buf[start] = buf[i];
				buf[i] = temp;
			}
		}

	}
}

分析:

超时,但是不会优化,希望以后会回来优化!

令start分别等于0,1,2,3....end并且多次调用perm方法形成多个循环,最外层镶嵌内层,内层再镶嵌内层。想不明白的时候可以按照图模拟一下(a,b,c,d)的全排列。

第二种做法:

 

12345找出这个序列全排列的第16个


计算方法就是如果你要求12345全排列的第16个的话
求第一位 用15/4!=0, 余15,那么前面有0个数,得到1。那么此时12345剩下了2345。
求第二位 用余的15/3! = 2, 余3,那么前面有2个数,得到4。剩下235。
求第三位 用余的3/2! = 1, 余1,那么前面有1个数,得到3,剩下25。
求第四位 用余的1/1! = 1, 余0,那么前面有1个数,得到5,剩下2。
求第五位 即2。

代码实现:


import java.math.BigInteger;
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		List<Integer>lists = new ArrayList<>();
		int[]arr = {0,1,2,3,4,5,6,7,8,9};
		int h = 0;
		int a = sc.nextInt();
		int n = a-1;
		int k = 9;
		for (int i = 0; i < arr.length; i++) {
			h=n/jie(k);
			n=n%jie(k);
			for (int j = 0; j < arr.length; j++) {
				if(h==0&!lists.contains(arr[j])) {
					lists.add(arr[j]);
					break;
				}else if(!lists.contains(arr[j])) {
					h--;
				}
			}
			k--;
		}
		Object[]arrs = lists.toArray();
		for (int i = 0; i < arrs.length; i++) {
			System.out.print(arrs[i]);
		}
	}
	public static int jie(int k ) {
		int sum = 1;
		for (int i = 1; i <=k; i++) {
			sum*=i;
		}
		return sum;
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章