本質
解決全排列問題本質是:二分法。
將某個數組的全排列看成是由第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}, {2, 1}},從分的角度看:可以看成先選出第0個位置應該是哪個數+其後所有數的全排列。二分後就可以將這變成1的情況。
- 對於{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;
}
}