字符串全排列算法

    問題:輸入一個字符串,打印出該字符串中字符的所有排列。例如輸入字符串abc,則輸出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。

      正常人的思維是,固定第一個字符,然後依次將後面的字符串與前面的交換,那麼排列的個數就是除了第一個字符以外,其他字符的排列個數+1。也就是固定一個字符串之後,之後再將問題變小,只需求出後面子串的排列個數就可以得出結果,當然第一時間想到的就是遞歸的算法了。下面這張圖很清楚的給出了遞歸的過程:



    很明顯,遞歸的出口,就是隻剩一個字符的時候,遞歸的循環過程,就是從每個子串的第二個字符開始依次與第一個字符交換,然後繼續處理子串。

代碼:

importjava.util.List;

import java.util.Collections;

import java.util.ArrayList;

public class Solution {

    public static void main(String[] args) {

        Solution p = new Solution();

        System.out.println(p.Permutation("abc").toString());

    }

   public ArrayList Permutation(String str) {

        List res = new ArrayList<>();

        if(str != null&& str.length() > 0) {

            PermutationHelper(str.toCharArray(), 0, res);

            Collections.sort(res);

        }

        return(ArrayList)res;

    }

    public void PermutationHelper(char[] cs, int i, List list) {

        if(i == cs.length - 1) {

            String val = String.valueOf(cs);

            if(!list.contains(val))

                list.add(val);

        } else{

            for(int j = i; j < cs.length; j++) {

                swap(cs, i, j);

                PermutationHelper(cs, i+1, list);

                swap(cs, i, j);

            }

        }

    }

    publicvoidswap(char[] cs, inti, intj) {

        chartemp = cs[i];

        cs[i] = cs[j];

        cs[j] = temp;

    }

}

    此處使得排列不重複使用的方法是判斷:   if(!list.contains(val))。

    還有一個問題要注意,就是如果字符串中有重複的字符串。由於全排列就是從第一個數字起,每個數分別與它後面的數字交換,我們先嚐試加個這樣的判斷——如果一個數與後面的數字相同那麼這兩個數就不交換 了。例如abb,第一個數與後面兩個數交換得bab,bba。然後abb中第二個數和第三個數相同,就不用交換了。但是對bab,第二個數和第三個數不 同,則需要交換,得到bba。由於這裏的bba和開始第一個數與第三個數交換的結果相同了,因此這個方法不行。

    換種思維,對abb,第一個數a與第二個數b交換得到bab,然後考慮第一個數與第三個數交換,此時由於第三個數等於第二個數,所以第一個數就不再用與第三個數交換了。再考慮bab,它的第二個數與第三個數交換可以解決bba。此時全排列生成完畢!

這樣,我們得到在全排列中去掉重複的規則:

去重的全排列就是從第一個數字起,每個數分別與它後面非重複出現的數字交換。


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