(1)問題描述:對於給定的集合 A{a1,a2,...,an},其中的 n 個元素互不相同,如何輸出這 n 個元素的所有排列(全排列),時間復雜度為O(2n);
例如:{a, b, c}
全排列:{a, b, c}, {a, c, b}, {b, a, c}, {b, c, a}, {c, a, b}, {c, b, a}
(2)回溯算法思想:
這里以 A{a, b, c} 為例,來說明全排列的生成方法,對於這個集合,其包含 3 個元素,所有的排列情況有 3!=6 種,對於每一種排列,其第一個元素有 3 種選擇 a, b, c,對於第一個元素為 a的排列,其第二個元素有 2 種選擇 b, c;第一個元素為 b 的排列,第二個元素也有2種選擇a,c,……,依次類推,我們可以將集合的全排列與一棵多叉樹對應。如下圖所示:

(3)算法代碼:
public class FullPermutation { /** * 存放數據數組 */ private static Integer[] data; /** * 數據數量 */ private static Integer num; /** * 交換數據 */ public static void swap(int x, int y) { Integer temp = data[x]; data[x] = data[y]; data[y] = temp; } /** * 初始化數據 */ private static void initData() { Scanner input = new Scanner(System.in); System.out.println("請輸入數據數量:"); num = input.nextInt(); System.out.println("請輸入數組數據"); data = new Integer[num]; for (int i = 0; i < data.length; i++) { data[i] = input.nextInt(); } } /** * 遞歸回溯排列樹求解 */ private static void backtrack(int t) { if (t == data.length) { System.out.print("排列樹為: "); Stream.of(data).forEach(element -> System.out.print(element + " ")); System.out.println(); } for (int i = t; i < data.length; i++) { swap(t, i); backtrack(t + 1); swap(t, i); } } public static void main(String[] args) { // 初始化數據 initData(); // 遞歸回溯排列樹求解 backtrack(0); } }
(4)輸入輸出
請輸入數據數量: 4 請輸入數組數據 1 2 3 4 排列數為: 1 1 2 3 排列數為: 1 1 3 2 排列數為: 1 2 1 3 排列數為: 1 2 3 1 排列數為: 1 3 2 1 排列數為: 1 3 1 2 排列數為: 1 1 2 3 排列數為: 1 1 3 2 排列數為: 1 2 1 3 排列數為: 1 2 3 1 排列數為: 1 3 2 1 排列數為: 1 3 1 2 排列數為: 2 1 1 3 排列數為: 2 1 3 1 排列數為: 2 1 1 3 排列數為: 2 1 3 1 排列數為: 2 3 1 1 排列數為: 2 3 1 1 排列數為: 3 1 2 1 排列數為: 3 1 1 2 排列數為: 3 2 1 1 排列數為: 3 2 1 1 排列數為: 3 1 2 1 排列數為: 3 1 1 2
(5)總結:回溯算法是有一定的規律可循的,根據問題,找出解空間的組織結構,選擇恰當的解決方案:回溯算法模板。
回溯算法一般采用深度優先的方式,遞歸求解,人的思維一般對遞歸求解的問題有一定的想象難度,建議在紙上根據代碼的流程,畫一畫走一遍詳細的過程,便於理解回溯算法的核心要點。
