/**
* 功能:肯定某字符串的全部排列組合。java
*/算法
注意:不考慮重複字符。若考慮重複字符,只需在加入permulations時去掉重複的字符串便可。編程
[java] view plain copyapp
一,問題描述spa
給定一個字符串,求出該字符串的全排列。.net
好比:"abc"的全排列是:abc、acb、bac、bca、cab、cbablog
二,實現思路遞歸
採用遞歸的方式求解。每次先選定一個字符,而後進行「若干次」交換,求出在選定這個字符的條件下,全部的全排列,並把字符「復位」再交換回來。至此,一趟全排列完成。第二趟,選定下一個字符,而後進行「若干次」交換,求出在選定這個字符的條件下,全部的全排列,並把字符「復位」再交換回來。.....ip
就相似於:(參考網上的解釋以下:)rem
設R={r1,r2,...rn}是要進行排列的n個元素.Ri=R-{ri}.集合X中元素的全排列記爲
Perm(X).(ri)Perm(X)表示在全排列Perm(X)的每個排列前加上前綴ri獲得的排列
R的全排列可概括定義以下:
當n=1時,Perm(R)=(r),其中r是集合R中惟一的元素;
當r>1時,Perm(R)由(r1)Perm(r1),(r2)Perm(r2).....(rn)Perm(rn)構成.
全排列就是從第一個數字起每一個數分別與它後面的數字交換
去重的全排列就是從第一個數字起每一個數分別與它後面非重複出現的數字交換, 用編程的話描述就是第i個數與第j個數交換時,要求[i,j)中沒有與第j個數相等的數。
代碼實現以下:使用一個LinkedList<String>保存每一種排列,若是字符串中出現有重複的字符,則此方法會求出 重複的排列數,於是LinkedList<String>會保存重複的排列。
import java.util.Collections; import java.util.LinkedList; public class Permutation { public static void allPermutation(String str){ if(str == null || str.length() == 0) return; //保存全部的全排列 LinkedList<String> listStr = new LinkedList<String>(); allPermutation(str.toCharArray(), listStr, 0); print(listStr);//打印全排列 } private static void allPermutation(char[] c, LinkedList<String> listStr, int start){ if(start == c.length-1) listStr.add(String.valueOf(c)); else{ for(int i = start; i <= c.length-1; i++) { swap(c, i, start);//至關於: 固定第 i 個字符 allPermutation(c, listStr, start+1);//求出這種情形下的全部排列 swap(c, start, i);//復位 } } } private static void swap(char[] c, int i, int j){ char tmp; tmp = c[i]; c[i] = c[j]; c[j] = tmp; } private static void print(LinkedList<String> listStr) { Collections.sort(listStr);//使字符串按照'字典順序'輸出 for (String str : listStr) { System.out.println(str); } System.out.println("size:" + listStr.size()); } //hapjin test public static void main(String[] args) { // allPermutation("hapjin"); allPermutation("abc"); } }
若是要想讓重複的排列只保存一次,有兩種方式:①改進算法,不生成重複的排列 ②用HashSet來保存排列
那當字符串中出現重複的字符時,如何生成不重複的排列?---去重的全排列就是從第一個數字起每一個數分別與它後面非重複出現的數字交換
代碼實現以下:(當有重複字符時,也可生成全部正確的排列(排列不會重複))
public class Permutation { public static void allPermutation(String str){ if(str == null || str.length() == 0) return; //保存全部的全排列 LinkedList<String> listStr = new LinkedList<String>(); allPermutation(str.toCharArray(), listStr, 0); print(listStr);//打印全排列 } private static void allPermutation(char[] c, LinkedList<String> listStr, int start){ if(start == c.length-1) listStr.add(String.valueOf(c));//System.out.println(String.valueOf(c)); else{ for(int i = start; i <= c.length-1; i++) { //只有當沒有重疊的字符 才交換 if(!isSwap(c, start, i)) { swap(c, i, start);//至關於: 固定第 i 個字符 allPermutation(c, listStr, start+1);//求出這種情形下的全部排列 swap(c, start, i);//復位 } } } } private static void swap(char[] c, int i, int j){ char tmp; tmp = c[i]; c[i] = c[j]; c[j] = tmp; } private static void print(LinkedList<String> listStr) { Collections.sort(listStr);//使字符串按照'字典順序'輸出 for (String str : listStr) { System.out.println(str); } System.out.println("size:" + listStr.size()); } //[start,end) 中是否有與 c[end] 相同的字符 private static boolean isSwap(char[] c, int start, int end) { for(int i = start; i < end; i++) { if(c[i] == c[end]) return true; } return false; } //hapjin test public static void main(String[] args) { // allPermutation("hapjin"); allPermutation("aba"); } }
上面的實現將全部的排列順序都保存到LinkedList<String>了,這是要注意的。固然也能夠不保存排列的順序,直接輸出(allPermutation方法)。
if(start == c.length-1) listStr.add(String.valueOf(c));//保存排列 //System.out.println(String.valueOf(c));//不保存排列,直接輸出