全排列算法本質與實現

本質

解決全排列問題本質是:二分法。
將某個數組的全排列看成是由第0個元素與其後所有元素的全排列組成

做法是每次只需要挑選某個元素作爲當前排列的第0個元素,然後剩下的變成子問題遞歸來解決。

原理

設一個數組的長度爲n,則其全排列的個數爲n!個。

設f(n)代表對於一個n長度數組的全排列,array(n)代表數組中的第n個元素,+代表拼接。

f(n) = array(1 to n) + f(n - 1)

由此可以看出這個算法需要利用遞歸來解決問題。每次只需要挑選某個元素作爲第0個元素,然後剩下的變成子問題遞歸來解決。

例子:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

我們可以從交換的角度和二分(大問題分解成小問題)的角度去思考。我們從交換的角度出發去思考應該如何交換才能形成全排列,從二分的角度思考如何劃分子問題。

  1. 對於{1},這個排列只有其本身,於是可以看成自身與自身交換。
  2. 對於{1,2},排列爲{{1, 2}, {2, 1}},從分的角度看:可以看成先選出第0個位置應該是哪個數+其後所有數的全排列。二分後就可以將這變成1的情況。
  3. 對於{1, 2, 3},同樣是第0個元素可以是1或2或3,然後子問題變成2的情況。

題目

描述

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

輸入描述: 輸入一個字符串,長度不超過9(可能有字符重複),字符只包括大小寫字母。

實現

import java.util.ArrayList;
import java.util.TreeSet;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        TreeSet<String> r = new TreeSet<>();
        DFS(r, str.toCharArray(), 0, str.length());
        ArrayList<String> result = new ArrayList<>(r.size());
        for (String s : r) {
            result.add(s);
        }
        return result;
    }
    
    public static void DFS(TreeSet<String> result,char[] str, int begin, int end) {
        if (begin + 1 == end) {
            result.add(new String(str));
        }
        
        for (int i = begin; i < end; i++) {
            swap(str, begin, i);
            
            DFS(result, str, begin + 1, end);
            
            swap(str, begin, i);
        }
    }
    
    public static void swap(char[] array, int aPos, int bPos) {
        char t = array[aPos];
        array[aPos] = array[bPos];
        array[bPos] = t;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章