89. Gray Code --迭代 和 back tracking 兩種方法
阿新 • • 發佈:2018-11-12
產生格雷碼,格雷碼就是前後 兩個數在二進位制上只有一個bit 的差別
先看看格雷碼的規律:
n =0, [0]
n=1, [0 1]
n=2: 00
01
11
10
n=3: 000
001
011
010
-----------------------------
110
111
101
100
可以發現規律, 比如 n=3 時相比於 n=2 時, 前面 4個數字和 n=2 時一樣, 後四個數字 就是 在n=2 時結果從後往前 前2 bits 不變, 然後在最高位上新增1, 因此很容易得到一個迭代的演算法,code 如下:
class Solution { public List<Integer> grayCode(int n) { List<Integer> result = new ArrayList<>(); if(n <0) return result; result.add(0); for(int i=0; i<n; i++){ int inc = 1<<i; int size = result.size(); for(int j=size-1; j>=0;j--){ result.add(result.get(j)+inc); } } return result; } }
code 雖然簡單,但一開始被我寫錯了兩處:
1. 2^n 寫成了 2<<n, 正確的是 1<<i
2. for(int j = result.size()-1; j>=0; j--) : 因為 result.size() 會不斷增加,所以得先取出 size 。
back tracking 解法:
畫一個遞迴數就明白了: 本質上就是一個二叉樹,問題是每次到底是先放 0 還是先放1。 觀察可以發現規律: 如果當前路徑下 1的個數為 偶數個,就放 left =0, right =1, 如果當前路徑下 1的個數為奇數,就放left = 1, right =0.
為了統計 當前路徑下 1的個數,設計了一個Node 節點,裡面的count 表示當前 1的個數。
class Solution { public List<Integer> grayCode(int n) { List<Integer> result = new ArrayList<>(); dfs(new Node(), result, n); return result; } private void dfs(Node curResult,List<Integer> result, int n){ if(curResult.list.size() == n){ int sum=0; for(int i=0; i<n; i++){ sum += curResult.list.get(n-i-1) << i; } result.add(sum); return; } if(curResult.count%2 ==0){ // 1的個數為偶數個,先放0 再放1 //left : curResult.list.add(0); dfs(curResult,result,n); curResult.list.remove(curResult.list.size()-1); //right curResult.list.add(1); curResult.count ++; dfs(curResult,result,n); curResult.list.remove(curResult.list.size()-1); curResult.count --; } else { // 1的個數為奇數個, 先放1, 再放0 //left curResult.list.add(1); curResult.count ++; dfs(curResult,result,n); curResult.list.remove(curResult.list.size()-1); curResult.count --; //right curResult.list.add(0); dfs(curResult,result,n); curResult.list.remove(curResult.list.size()-1); } //right tree } } class Node { List<Integer> list; int count; Node(){ list = new ArrayList<>(); count = 0; } }