給定一個無重複字符的字符串數組,實現它的全排列java
思想是從第一個字符開始排,一直排到只有一個字符那麼就說明一個排列完成了。不然就交換當前第k個字符和第i個字符(這裏的第i個字符指的是k後面全部字符的其中一個,例如abcd,當a固定,對bcd排列,那就要將b和c、b和d依次交換),再對k+1到m進行排列。當返回成功後就再將第k個字符和第i個字符再交換回來。數組
遞歸的終止條件就是k=m函數
k 爲起始下標,m爲結束下標,下面的函數用於返回從k到m的全排列測試
list[]用於存儲待排列的字符串spa
public static void perm(char list[], int k, int m) { if(k == m) { System.out.println(list); } else { for(int i = k; i <= m; i++) { //交換第k個字符和第i個字符,由於java是按值傳遞,因此我就沒用函數交換 char temp; temp = list[k]; list[k] = list [i]; list[i] = temp; //再對k後面的字符串進行全排列 perm(list, k+1, m); //排列完後再換回來繼續下一層循環 temp = list[k]; list[k] = list [i]; list[i] = temp; } } }
思想是深度優先搜索,好比要找12345的全排列的一種排列12345code
第一層,有五種選擇,一、二、三、四、5,五個元素都標記沒被使用過遞歸
第二層,1下面有四種二、三、四、5, 1被標記使用過字符串
第三層,2下面有三種三、四、5, 一、2被標記使用過input
第四層,3下面有兩種四、5, 一、二、3被標記使用過string
第五層,4下面就只能排5了,一、二、三、4被標記使用過
這時就找到了一種排列12345,而後將5標記爲沒被使用過,返回到上一層4,將4也標記爲沒使用過,但5能夠選,而後再選4,這樣就實現了回溯,就能夠獲得全部解了。
具體代碼以下:
參數n表示第幾層,list是一個char型的數組,存放了待全排列的字符串
used[]是一個bool型的數組,具體下標對應的真假值判斷那個下標的字符有沒有被使用過,vector[]是一個整型數組,用於存放一個排列的解,amount用於計數,result函數用於將解向量輸出成排列。
public static void perm(char list[], int k, int m) { if(k == m) { System.out.println(list); } else { for(int i = k; i <= m; i++) { //交換 char temp; temp = list[k]; list[k] = list [i]; list[i] = temp; //返回k以後的全排列 perm(list, k+1, m); //交換回來 temp = list[k]; list[k] = list [i]; list[i] = temp; } } }
完整的能夠經過輸入字符串(要保證無重複字符)來返回全部排列的測試代碼以下:
import java.nio.file.attribute.AclEntryPermission; import java.util.Arrays; import java.util.Scanner; public class Generator { static boolean used[];//存放字符是否被使用過 static char list[];//存放字符串 static int vector[];//存放當前排列的解向量 static int amount = 0;//用於計數 public static void main(String[] args) { // 用戶輸入字符串 String str; Scanner input = new Scanner(System.in); str = input.next(); list = str.toCharArray(); used = new boolean[str.length()]; vector = new int[str.length()]; //perm(list, 0, str.length()-1); //用遞歸實現全排列 Aperm(0);//用回溯實現全排列,從第0層開始 } public static void perm(char list[], int k, int m) { if(k == m) { System.out.println(list); } else { for(int i = k; i <= m; i++) { //交換 char temp; temp = list[k]; list[k] = list [i]; list[i] = temp; //返回k以後的全排列 perm(list, k+1, m); //交換回來 temp = list[k]; list[k] = list [i]; list[i] = temp; } } } public static void Aperm(int n) { //第0層有i.length種選擇 for(int i = 0; i < list.length; i++) { if(!used[i]) { vector[n] = i;//記錄當前解 used[i] = true;//當前元素被使用 if(n!= list.length - 1) Aperm(n+1);//若不是最後一層則返回下一層的 else//不然就是最後一層,那麼就找到了一種排列,輸出 System.out.println(amount++ +": "+ result(vector)); //很重要,返回到上一層就得取消標記 used[i] = false; } } } public static String result(int vector[]) { String string = ""; for(int i = 0; i < vector.length; i++) { string += list[vector[i]]; } return string; } }