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;
}
}