全排列與康拓逆展開

(算法)全排列的遞歸算法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;
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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