連結:https://www.nowcoder.com/questionTerminal/fe6b651b66ae47d7acce78ffdd9a96c7
來源:牛客網
輸入一個長度為 n 字串,列印出該字串中字元的所有排列,你可以以任意順序返回這個字串陣列。
例如輸入字串ABC,則輸出由字元A,B,C所能排列出來的所有字串ABC,ACB,BAC,BCA,CBA和CAB。
/**
* 1、遞迴演算法
*
* 解析:http://www.cnblogs.com/cxjchen/p/3932949.html (感謝該文作者!)
*
* 對於無重複值的情況
*
* 固定第一個字元,遞迴取得首位後面的各種字串組合;
* 再把第一個字元與後面每一個字元交換,並同樣遞迴獲得首位後面的字串組合; *遞迴的出口,就是隻剩一個字元的時候,遞迴的迴圈過程,就是從每個子串的第二個字元開始依次與第一個字元交換,然後繼續處理子串。
*
* 假如有重複值呢?
* *由於全排列就是從第一個數字起,每個數分別與它後面的數字交換,我們先嚐試加個這樣的判斷——如果一個數與後面的數字相同那麼這兩個數就不交換了。
* 例如abb,第一個數與後面兩個數交換得bab,bba。然後abb中第二個數和第三個數相同,就不用交換了。
* 但是對bab,第二個數和第三個數不 同,則需要交換,得到bba。
* 由於這裡的bba和開始第一個數與第三個數交換的結果相同了,因此這個方法不行。
*
* 換種思維,對abb,第一個數a與第二個數b交換得到bab,然後考慮第一個數與第三個數交換,此時由於第三個數等於第二個數,
* 所以第一個數就不再用與第三個數交換了。再考慮bab,它的第二個數與第三個數交換可以解決bba。此時全排列生成完畢!
*
*
* @param str
* @return
*/
public ArrayList<String> Permutation(String str){
ArrayList<String> list = new ArrayList<String>();
if(str!=null && str.length()>0){
PermutationHelper(str.toCharArray(),0,list);
Collections.sort(list);
}
return list;
}
private void PermutationHelper(char[] chars,int i,ArrayList<String> list){
if(i == chars.length-1){
list.add(String.valueOf(chars));
}else{
Set<Character> charSet = new HashSet<Character>();
for(int j=i;j<chars.length;++j){
if(j==i || !charSet.contains(chars[j])){
charSet.add(chars[j]);
swap(chars,i,j);
PermutationHelper(chars,i+1,list);
swap(chars,j,i);
}
}
}
}
private void swap(char[] cs,int i,int j){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
/**
* 2、字典序排列演算法
*
* 可參考解析: http://www.cnblogs.com/pmars/archive/2013/12/04/3458289.html (感謝作者)
*
* 一個全排列可看做一個字串,字串可有字首、字尾。
* 生成給定全排列的下一個排列.所謂一個的下一個就是這一個與下一個之間沒有其他的。
* 這就要求這一個與下一個有儘可能長的共同字首,也即變化限制在儘可能短的字尾上。
*
* [例]839647521是1--9的排列。1—9的排列最前面的是123456789,最後面的987654321,
* 從右向左掃描若都是增的,就到了987654321,也就沒有下一個了。否則找出第一次出現下降的位置。
*
* 【例】 如何得到346987521的下一個
* 1,從尾部往前找第一個P(i-1) < P(i)的位置
* 3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
* 最終找到6是第一個變小的數字,記錄下6的位置i-1
*
* 2,從i位置往後找到最後一個大於6的數
* 3 4 6 -> 9 -> 8 -> 7 5 2 1
* 最終找到7的位置,記錄位置為m
*
* 3,交換位置i-1和m的值
* 3 4 7 9 8 6 5 2 1
* 4,倒序i位置後的所有資料
* 3 4 7 1 2 5 6 8 9
* 則347125689為346987521的下一個排列
*
* @param str
* @return
*/
public ArrayList<String> Permutation2(String str){
ArrayList<String> list = new ArrayList<String>();
if(str==null || str.length()==0){
return list;
}
char[] chars = str.toCharArray();
Arrays.sort(chars);
list.add(String.valueOf(chars));
int len = chars.length;
while(true){
int lIndex = len-1;
int rIndex;
while(lIndex>=1 && chars[lIndex-1]>=chars[lIndex]){
lIndex--;
}
if(lIndex == 0)
break;
rIndex = lIndex;
while(rIndex<len && chars[rIndex]>chars[lIndex-1]){
rIndex++;
}
swap(chars,lIndex-1,rIndex-1);
reverse(chars,lIndex);
list.add(String.valueOf(chars));
}
return list;
}
private void reverse(char[] chars,int k){
if(chars==null || chars.length<=k)
return;
int len = chars.length;
for(int i=0;i<(len-k)/2;i++){
int m = k+i;
int n = len-1-i;
if(m<=n){
swap(chars,m,n);
}
}
}