1. 程式人生 > 實用技巧 >全排列演算法及解決數字搭積木問題

全排列演算法及解決數字搭積木問題

如果你是做這道題不會,那麼你可以看這道題的解題思路,如果你是不太理解全排列演算法,那麼你可以通過這個題來理解。

題目描述:

小明最近喜歡搭數字積木。一共有10塊積木,每個積木上有一個數字,0~9。

搭積木規則:
每個積木放到其它兩個積木的上面,並且一定比下面的兩個積木數字小
最後搭成4層的金字塔形,必須用完所有的積木。

下面是兩種合格的搭法:

請你計算這樣的搭法一共有多少種?

分析

一共有10個數字,要我們把所有可行的排列方式都求出來,一時沒什麼思路,索性就全排列了,把所有排列的情況都求出來,然後在把每種情況都判斷一下,是不是就可以得到答案了。

所以全排列怎麼寫成了第一大問題了。

全排列

對於這個問題來說,我們把金字塔當成一個int陣列,那麼就為 全排列這個陣列{0,1,2,3,4,5,6,7,8,9}。

太長了,想不明白呀,所以來看比較少的唄。
對於{0,1}全排列,就是把0抽出來,1做全排列,對於{0,1,2},就是:

  1. 把0抽出來,把1,2做全排列,
  2. 把1抽出來,把0,2做全排列,
  3. 把2抽出來,把0,1做全排列。
  4. 接下來那不就和上面那個{0,1}一樣了嗎?

這是不是個遞迴呢?很明顯吧。的確是。

那好我們定義一個方法,這個方法的作用是,把list陣列全排列,而引數curr表示當前抽出來的那個數,就像上面例子提到的0一樣。

提出來了之後呢,是不是要把curr交換了,這樣就可以把所有在這個位置上的所有情況列出來了,所以使用一個for迴圈,來交換curr和後面剩餘陣列的數(就是上面例子的1,2,3步驟)。

緊接著定義一個方法,交換兩數swap(list,curr,j);

,當然你也可以把這個方法直接寫到這個函式裡面,但是畢竟不美觀,不實用。

重點來了:回溯!!!

從這張圖中,所謂回溯就是要回到上一沒有操作過的狀態,再去考慮別的情況。就下面這個A,B,C他需要回到上一次抽數出來之前的狀態。這樣他才能去抽另外一個數,全排列下一種情況。所以我們需要在寫一遍swap(list,curr,j);

問題分析到這了,我們的程式碼基本上就可以出來了,所以看下程式碼,如果看不懂在回到我的分析,相信你一定能看懂。

public class Test2 {
    static int sum ;
    public static void main(String[] args) {
        int list[] = {0,1,2,3,4,5,6,7,8,9};
        allSort(list,0);
        System.out.println(sum);
    }
    //代表將第a[m]和a[n]相交換
    public static void swap(int a[],int m ,int n){
        int temp = a[m];
        a[m] = a[n];
        a[n] = temp;
    }
    //呼叫全排列陣列list,curr代表當前放在第一個的為第幾個數字,比如開始就為陣列第0個數字
    public static void allSort(int list[],int curr ){
        //如果當前陣列的索引等於陣列的長了,就將方法加1
        if (curr == list.length-1){
            check(list);
        }else {
            //陣列每一個都要和當前陣列的第curr個相交換,所以要用個迴圈
            for (int j = curr; j < list.length; j++){
                swap(list,curr,j);
                allSort(list,curr+1);
                swap(list,curr,j);
            }
        }
    }
    public static void check(int list[]){
        if (list[1] < list[0]) return;
        if (list[2] < list[0]) return;
        if (list[3] < list[1]) return;
        if (list[4] < list[1]) return;
        if (list[4] < list[2]) return;
        if (list[5] < list[2]) return;
        if (list[6] < list[3]) return;
        if (list[7] < list[3]) return;
        if (list[7] < list[4]) return;
        if (list[8] < list[4]) return;
        if (list[8] < list[5]) return;
        if (list[9] < list[5]) return;
        sum++;

    }

}

其實這個全排列都可以當成一個模板了,但是還是推薦大家一定要手敲,自己寫程式碼,寫出來了,才是自己的東西。

圖片參考:https://blog.csdn.net/Strom72/article/details/80738818