天天看点

779. 第K个语法符号 : 正难则反,倒推验证

题目描述

这是 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 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。