[LeetCode] K-th Symbol in Grammar 語法中的第K個符號
On the first row, we write a 0
. Now in every subsequent row, we look at the previous row and replace each occurrence of 0
with 01
, and each occurrence of 1
with 10
.
Given row N
and index K
, return the K
-th indexed symbol in row N
. (The values of K
are 1-indexed.) (1 indexed).
Examples: Input: N = 1, K = 1 Output: 0 Input: N = 2, K = 1 Output: 0 Input: N = 2, K = 2 Output: 1 Input: N = 4, K = 5 Output: 1 Explanation: row 1: 0 row 2: 01 row 3: 0110 row 4: 01101001
Note:
N
will be an integer in the range[1, 30]
.K
will be an integer in the range[1, 2^(N-1)]
.
這道題說第一行寫上了一個0,然後從第二行開始,遇到0,就變為01,遇到1,則變為10,問我們第N行的第K個數字是啥。這是一道蠻有意思的題目,首先如果沒啥思路的話,按照給定的方法,一行行generate出來,直到生成第N行,那麼第K個數字也就知道了。但是這種brute force的方法無法通過OJ,這裡就不多說了,需要想一些更高階的解法。我們想啊,遇到0變為01,那麼可不可以把0和1看作上一層0的左右子結點呢,同時,把1和0看作上一層1的左右子結點,這樣的話,我們整個結構就可以轉為二叉樹了,那麼前四層的二叉樹結構如下所示:
0
/ \
0 1
/ \ / \
0 1 1 0
/ \ / \ / \ / \
0 1 1 0 1 0 0 1
我們仔細觀察上面這棵二叉樹,第四層K=3的那個紅色的左子結點,其父結點的位置是第三層的第 (K+1)/2 = 2個紅色結點,而第四層K=6的那個藍色幽子結點,其父節點的位置是第三層的第 K/2 = 3個藍色結點。那麼我們就可以一層一層的往上推,直到到達第一層的那個0。所以我們的思路是根據當前層K的奇偶性來確定上一層中父節點的位置,然後繼續往上一層推,直到推倒第一層的0,然後再返回確定路徑上每一個位置的值,這天然就是遞迴的執行機制啊。我們可以根據K的奇偶性知道其是左結點還是右結點,由於K是從1開始的,所以當K是奇數時,其是左結點,當K是偶數時,其是右結點。而且還能觀察出來的是,左子結點和其父節點的值相同,右子結點和其父節點值相反,這是因為0換成了01,1換成了10,左子結點保持不變,右子結點flip了一下。想通了這些,那麼我們的遞迴解法就不難寫出來了,參見程式碼如下:
解法一:
class Solution { public: int kthGrammar(int N, int K) { if (N == 1) return 0; if (K % 2 == 0) return (kthGrammar(N - 1, K / 2) == 0) ? 1 : 0; else return (kthGrammar(N - 1, (K + 1) / 2) == 0) ? 0 : 1; } };
我們可以簡化下上面的解法,你們可能會說,納尼?已經三行了還要簡化?沒錯,博主就是這樣一個精益求精的人(此處應有掌聲