1. 程式人生 > >全排列之JAVA實現

全排列之JAVA實現

全排列的基本思想是:
把待全排列記錄分為兩個部分:
(1) 第一個記錄
(2) 剩下的所有元素
所有記錄的全排列就是所有可能出現在第一個位置的記錄與剩下所有元素的全排列
以[1,2,3]為例,
1,2,3的全排列可以看作是
   1,[2,3的全排列]
      [2,3]的全排列又可以看作是
         2,[3的全排列]—————對應123
         3,[2的全排列]—————對應132
   2,[1,3的全排列]
      [1,3]的全排列又可以看作是
         1,[3的全排列]—————對應213
         3,[1的全排列]—————對應231
   3,[1,2的全排列]
      [1,2]的全排列又可以看作是
         1,[2的全排列]—————對應312
         2,[1的全排列]—————對應321

所以很明顯,這就是一個遞迴的思想:給你部分記錄,全排列就是所有可能出現在第一個位置的記錄與剩下的元素的全排列,剩下的元素的全排列又是剩下的可能出現在第一個位置的元素與剩下的元素的全排列,依次重複下去….

完整程式碼如下:
fullSort方法接收三個引數,陣列arr,起始位置start,終止為止end,意思就是完成arr陣列從start到end之間記錄的全排列。
分兩個步驟:
(1)確定第一位的字元
陣列arr從start到end的所有記錄都可以出現在第一個位置,所以直接一個for迴圈,考慮了這所有的情況。在for迴圈中,swap方法就是交換i和start位置的數,保證當前i指向的記錄出現在第一個位置,也就是start指向的位置
(2)剩下的記錄繼續做全排列
這個就是一個遞迴函式的呼叫,只需要修改起始位置,也就是start+1,因為start的位置已經放了記錄,所以只需要繼續做從start+1到end的全排列即可

至於緊接著的一個swap方法是做什麼的呢?因為陣列傳遞的是地址,所以所有的修改對所有人都是共享的,因此為了保證每一次的交換不會對下一次的交換產生影響,要重新交換一下位置,也就是復原,不然對下一次的交換就有影響了

遞迴的終止條件就是當start==end,也就是隻有一個記錄需要做全排列,也就是到了最後一個記錄,這就是全排列的一種情況,輸入本次的記錄,也就是陣列arr即可。

public class Main {
    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4 };
        fullSort(arr, 0
, arr.length - 1); } public static void fullSort(int[] arr, int start, int end) { // 遞迴終止條件 if (start == end) { for (int i : arr) { System.out.print(i); } System.out.println(); return; } for (int i = start; i <= end; i++) { swap(arr, i, start); fullSort(arr, start + 1, end); swap(arr, i, start); } } private static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } }

接下來用全排列來解決一個實際問題吧。

題目:圖書排列

題目描述:將編號為1~10的10本書排放在書架上,要求編號相鄰的書不能放在相鄰的位置。
請計算一共有多少種不同的排列方案。

注意,需要提交的是一個整數,不要填寫任何多餘的內容。

解題思路:這個題目有很多解法,這裡只說明用全排列怎麼解決,先求出全排列,也就是所有的排列方案,然後去掉不滿足條件的情況,也就是編號相鄰的書不能相鄰這一條件。

完整程式碼如下:

public class BookSort {

    public static void main(String[] args) {
        int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        fullSort(arr, 0, arr.length - 1);
        System.out.println(res);
    }

    static int res = 0;

    static void fullSort(int[] arr, int start, int end) {
        // 遞迴終止條件
        if (start == end) {
            // 求出了全排列的一種情況,然後檢查是否滿足條件
            if (check(arr))
                res++;
            return;
        }
        for (int i = start; i <= end; i++) {
            swap(arr, start, i);
            fullSort(arr, start + 1, end);
            swap(arr, start, i);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    static boolean check(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            if (Math.abs(arr[i] - arr[i - 1]) == 1)
                return false;
        }
        return true;
    }

}

全排列的程式碼和上面的程式碼一樣,不同的地方就是在找到全排列的一種情況時,要檢查是否滿足條件,也就是check方法。

執行結果:479306