1. 程式人生 > >LeetCode 89 gray code 格雷編碼

LeetCode 89 gray code 格雷編碼

題目連結

https://leetcode-cn.com/problems/gray-code/

題意

        有可能是因為機翻,題目描述不太清楚。學過數位電路的應該能秒懂了。實際上就是給出一個n,那麼有[0,2^n-1]總共2^n個數。現在對這些數進行排序放在List裡,要求按照格雷編碼的形式。格雷編碼是相鄰兩個數的二進位制只有一位是不同的,例如1、3可以相鄰,其二進位制為01和11,只有1位不同。而題目要求所有的相鄰的兩個數之間都是隻有一位不同。

題解

        據說Google面試題,挺考思維的。剛開始很懵,不知道從哪裡開始下手好,冥冥之中感覺是要找規律,畢竟是按照格雷碼來,每次換一位的話,是否能夠按照一定的順序輪著換,這樣既能保證是格雷編碼,同時又不會把中間的數給漏掉。並且二進位制如果只對一位進行反轉,那麼直接異或運算就行了,可實施程度也比較高。然後就有下面的圖:

主要是中間紅框內容。是0-15的二進位制,而且相鄰都是差一位。弧度擴的1、2、3等數字代表前一個數與後一個數相比,第幾位翻轉了。這是在研究n = 4的時候發現的。那麼其翻轉位的順序為:

n = 2       1 2 1

n = 3       1 2 1 3 1 2 1

可以發現,位數“很慫”,一定要保證每次高位翻轉一次就要到最低位再翻轉一次。所以試著寫出來了上圖。那麼:

n = 4       1 2 1 3 1 2 1 4 1 2 1 3 1 2 1

同時對比這3種情況,發現翻轉是以迴文數的形式進行的,以n為軸,以n-1的情況為兩側資料。那麼對於i,構造出來一側的情況,加上i+1,在將一側給複製過去,就得到了i+1的翻轉情況。這樣,在一次for迴圈中就可以得到n的翻轉情況。有程式碼:

public static void init(int n){
    N = n;
    grayconfig = new ArrayList<Integer>();
    grayconfig.add(2);
    for(int i = 3;i <= N;i++){
        ArrayList<Integer> temp = (ArrayList<Integer>) grayconfig.clone();
        grayconfig.add(i);
        for(int j = 0;j < temp.size();j++){
            grayconfig.add(temp.get(j));
        }
    }
}

這裡我簡寫了,對於0到1的轉換就沒寫進去,所以第一位一定是2,然後從第二位開始計算就可以了。因為我們要構造迴文,所以計算出一側以後,利用clone,直接clone到後面。這樣也不用考慮範圍問題。 

        接下來就好辦了,既然知道了如何翻轉,那麼對於陣列中i位應該放誰,就把i-1位進行對應的翻轉後存進陣列即可。翻轉這裡利用異或。例如我們對於二進位制110110的第二位翻轉想得到110100,那麼我們可以:

110110 xor 000010 = 110100

而這個異或的值也非常簡單,1後面n個0,明顯是2^n,也就是說,可以得到方法:

public static int flip(int number,int index){
    int bit = (int) Math.pow(2,index-1);
    return number^bit;
}

就能翻轉了。按照上面寫的,輪次翻轉就能得到最終答案。

        但是這樣就忽略了特殊情況:n = 0和n = 1。n = 0的時候應該有2^0 = 1位,因為第一位要是0開頭,所以就是0。n = 1的時候是2^1 = 2,那麼0開頭以後,下面是1就完事了,這兩個判定以後,其他就正常了。

Java 程式碼

import java.util.List;

class Solution {
    public static int N;
    public static ArrayList<Integer> grayconfig;
    
    public static void init(int n){
        N = n;
        grayconfig = new ArrayList<Integer>();
        grayconfig.add(2);
        for(int i = 3;i <= N;i++){
            ArrayList<Integer> temp = (ArrayList<Integer>) grayconfig.clone();
            grayconfig.add(i);
            for(int j = 0;j < temp.size();j++){
                grayconfig.add(temp.get(j));
            }
        }
    }
    
    public static int flip(int number,int index){
        int bit = (int) Math.pow(2,index-1);
        return number^bit;
    }
    
    public List<Integer> grayCode(int n) {
        List<Integer> ans = new ArrayList<Integer>();
        ans.add(0);
        if(n == 0) return ans;
        if(n == 1){
            ans.add(1);
            return ans;
        }
        init(n);
        int number = 0;
        number = flip(number,1);
        ans.add(number);
        for(int i = 0;i < grayconfig.size();i++){
            number = flip(number,grayconfig.get(i));
            ans.add(number);
            number = flip(number,1);
            ans.add(number);
        }
        return ans;
    }
}