題目描述
這是 LeetCode 上的 779. 第K個文法符号 ,難度為 中等。
Tag : 「DFS」、「遞歸」
我們建構了一個包含
n
行( 索引從
1
開始 )的表。首先在第一行我們寫上一個
0
。接下來的每一行,将前一行中的
0
替換為
01
,
1
替換為
10
。
- 例如,對于
,第n = 3
行是1
,第0
行是2
,第01
行是3
。0110
給定行數
n
和序數
k
,傳回第
n
行中第
k
個字元。(
k
從索引
1
開始)
示例 1:
輸入: n = 1, k = 1
輸出: 0
解釋: 第一行:0
示例 2:
輸入: n = 2, k = 1
輸出: 0
解釋:
第一行: 0
第二行: 01
示例 3:
輸入: n = 2, k = 2
輸出: 1
解釋:
第一行: 0
第二行: 01
提示:
遞歸(倒推驗證)
整理一下條件:首行為
0
,每次用目前行拓展出下一行時,字元數量翻倍(将
0
拓展為
01
,将
1
拓展為
10
),且字元種類仍為
01
。
要求我們輸出第 行第 列的字元,我們可以通過「倒推驗證」的方式來求解:假設第 行第 為
1
,若能倒推出首行為 ,說明假設成立,傳回
1
,否則傳回
0
。
倒推驗證可通過實作遞歸函數
int dfs(int r, int c, int cur)
來做,含義為當第 行第 列的字元為
- 若「目前列為偶數且」或「目前列為奇數且」時,說明目前列所在的組為
,由此可推出其是由上一行的10
拓展而來,結合每次拓展新行字元數量翻倍的條件,可知是由第行的第列的1
拓展而來,遞歸處理;1
- 否則,同理,必然是上一行(第行)對應位置的
拓展而來,遞歸處理。0
最終,當倒推到首行時,我們找到了遞歸出口,直接傳回
cur
。
Java 代碼:
class Solution {
public int kthGrammar(int n, int {
return dfs(n, k, 1) == 0 ? 1 : 0;
}
int dfs(int r, int c, int {
if (r == 1) return cur;
if ((c % 2 == 0 && cur == 0) || (c % 2 == 1 && cur == 1)) return dfs(r - 1, (c - 1) / 2 + 1, 1);
else return dfs(r - 1, (c - 1) / 2 + 1, 0);
}
}
TypeScript 代碼:
function kthGrammar(n: number, k: number): number {
function dfs(r: number, c: number, cur: number): number {
if (r == 1) return cur
if ((c % 2 == 0 && cur == 0) || (c % 2 == 1 && cur == 1)) return dfs(r - 1, Math.floor((c - 1) / 2) + 1, 1)
else return dfs(r - 1, Math.floor((c - 1) / 2) + 1, 0)
}
return dfs(n, k, 1) == 0 ? 1 : 0
Python 代碼:
class Solution:
def kthGrammar(self, n: int, k: int) -> int:
def dfs(r, c, cur):
if r == 1:
return cur
if (c % 2 == 0 and cur == 0) or (c % 2 == 1 and cur == 1):
return dfs(r - 1, (c - 1) // 2 + 1, 1)
else:
return dfs(r - 1, (c - 1) // 2 + 1, 0)
return 1 if dfs(n, k, 1) == 0 else 0
- 時間複雜度:
- 空間複雜度:忽略遞歸帶來的額外空間開銷,複雜度為
最後
這是我們「刷穿 LeetCode」系列文章的第
No.779
篇,系列開始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們将先把所有不帶鎖的題目刷完。
在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的代碼。如果涉及通解還會相應的代碼模闆。