题目描述
这是 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 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。