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