Medium

题目描述

我们构建一个有 n 行(从 1 开始编号)的表格。我们从第 1 行写 0 开始。现在在每一个后续行中,我们查看前一行并将每个 0 替换为 01,每个 1 替换为 10。

例如,对于 n = 3,第 1 行是 0,第 2 行是 01,第 3 行是 0110。

给定两个整数 n 和 k,返回第 n 行中第 k 个(从 1 开始编号)符号。

示例 1:

输入:n = 1, k = 1
输出:0
解释:第 1 行:0

示例 2:

输入:n = 2, k = 1
输出:0
解释:
第 1 行:0
第 2 行:01

示例 3:

输入:n = 2, k = 2
输出:1
解释:
第 1 行:0
第 2 行:01

提示:

  • 1 <= n <= 30
  • 1 <= k <= 2^(n-1)
  • 尝试用某个 (N-1, prevK) 来表示当前的 (N, K)。prevK 是什么?

解题思路

这道题可以通过观察规律用递归来解决。

首先分析构建规律:

  • 第1行:0
  • 第2行:01(0→01)
  • 第3行:0110(0→01, 1→10)
  • 第4行:01101001(0→01, 1→10, 1→10, 0→01)

关键观察:第 n 行的前半部分与第 n-1 行相同,后半部分是第 n-1 行的"翻转"(0变1,1变0)。

具体来说,对于第 n 行的第 k 个位置:

  1. 如果 k 在前半部分(k <= 2^(n-2)),则它等于第 n-1 行的第 k 个位置
  2. 如果 k 在后半部分(k > 2^(n-2)),则它等于第 n-1 行的第 (k - 2^(n-2)) 个位置的翻转

这样我们就可以递归地将问题规模减小,直到 n=1 时返回 0。

另一种思路是观察二进制规律:第 n 行第 k 个位置的值等于 (k-1) 的二进制表示中 1 的个数的奇偶性。

代码实现

class Solution {
public:
    int kthGrammar(int n, int k) {
        if (n == 1) return 0;
        
        int mid = 1 << (n - 2);  // 2^(n-2)
        if (k <= mid) {
            return kthGrammar(n - 1, k);
        } else {
            return 1 - kthGrammar(n - 1, k - mid);
        }
    }
};
class Solution:
    def kthGrammar(self, n: int, k: int) -> int:
        if n == 1:
            return 0
        
        mid = 2 ** (n - 2)
        if k <= mid:
            return self.kthGrammar(n - 1, k)
        else:
            return 1 - self.kthGrammar(n - 1, k - mid)
public class Solution {
    public int KthGrammar(int n, int k) {
        if (n == 1) return 0;
        
        int mid = 1 << (n - 2);  // 2^(n-2)
        if (k <= mid) {
            return KthGrammar(n - 1, k);
        } else {
            return 1 - KthGrammar(n - 1, k - mid);
        }
    }
}
var kthGrammar = function(n, k) {
    if (n === 1) return 0;
    
    let mid = Math.pow(2, n - 2);
    
    if (k <= mid) {
        return kthGrammar(n - 1, k);
    } else {
        return 1 - kthGrammar(n - 1, k - mid);
    }
};

复杂度分析

复杂度分析
时间复杂度O(n) - 递归深度为 n,每层递归只做常数时间操作
空间复杂度O(n) - 递归调用栈的深度为 n