返回

在 LeetCode 779 中轻松理解第 K 个语法符号

前端

导言

LeetCode 779: 第 K 个语法符号 是一道考察动态规划和递归思想的经典题。给定行数 N 和序数 K,要求找出第 N 行中第 K 个字符。这道题看似简单,但蕴含着深刻的编程技巧和数学规律。本文将深入浅出地解析这道题,带你领略算法之美。

问题背景

在计算机科学中,语法符号经常用于表示某种语言的结构和规则。在 LeetCode 779 中,我们有一个特殊的语法规则:

  • 第一行的第一个字符为 0
  • 对于每一行,将上一行的 0 替换为 01,将 1 替换为 10

给定行数 N 和序数 K,我们的任务是找出第 N 行中第 K 个字符。

思路解析

解决这道题的关键在于理解语法规则的本质。每一行的字符序列都是由上一行的字符序列经过某种替换规则生成的。我们可以利用这个规律,通过动态规划或递归的方式,逐步推导出第 N 行的字符序列,再根据 K 找出对应的字符。

动态规划解法

动态规划是一种自底向上的算法,它将问题分解成一系列子问题,并逐步解决这些子问题。对于这道题,我们可以定义一个二维数组 dp,其中 dp[i][j] 表示第 i 行第 j 个字符。

def kthGrammar(N, K):
    dp = [[0] * (K+1) for _ in range(N+1)]
    dp[1][1] = 0
    for i in range(2, N+1):
        for j in range(1, K+1):
            if dp[i-1][j] == 0:
                dp[i][j] = (j % 2 == 0)
            else:
                dp[i][j] = (j % 2 == 1)
    return dp[N][K]

递归解法

递归是一种自顶向下的算法,它将问题分解成较小的相同问题,并逐步解决这些子问题。对于这道题,我们可以定义一个递归函数 f(N, K),其中 f(N, K) 表示第 N 行第 K 个字符。

def kthGrammar(N, K):
    if N == 1:
        return 0
    if K % 2 == 0:
        return f(N-1, K/2)
    else:
        return 1 - f(N-1, (K+1)/2)

代码实现

以下是用 Python 实现的动态规划和递归解法:

动态规划解法

def kthGrammar(N, K):
    dp = [[0] * (K+1) for _ in range(N+1)]
    dp[1][1] = 0
    for i in range(2, N+1):
        for j in range(1, K+1):
            if dp[i-1][j] == 0:
                dp[i][j] = (j % 2 == 0)
            else:
                dp[i][j] = (j % 2 == 1)
    return dp[N][K]

递归解法

def kthGrammar(N, K):
    if N == 1:
        return 0
    if K % 2 == 0:
        return f(N-1, K/2)
    else:
        return 1 - f(N-1, (K+1)/2)

总结

LeetCode 779: 第 K 个语法符号 是一道经典的算法题,考察了动态规划和递归的思想。通过深入理解语法规则的本质,我们可以巧妙地运用这些算法解决问题。本文提供了两种解法,供读者参考学习。