LeetCode 每日一题:第K个语法符号

121 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 10 天,点击查看活动详情

第K个语法符号

原题地址

我们构建了一个包含 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

提示:

  • 1 <= n <= 30
  • 1 <= k <=2n2^n- 1

思路分析

根据题目来找规律,算下每一行的值:

  • 第一行:0
  • 第二行:0 1
  • 第三行:01 10
  • 第四行:0110 1001
  • 第五行:01101001 10010110
  • 第六行:0110100110010110 1001011001101001

可以发现,每一行的前半段就是上一行,而后半段就是上一行每个值反过来,那么针对题目可以分两种情况处理,k 在上半段或下半段。

  1. 若 n 为1,那么返回值为0;
  2. 计算当前行的长度为 2n12^{n-1};
  3. 如果 k 大于长度的一半,就在当前行的后半段,然后先得到上一行的值,位置为 k 在当前行后半段的位置,然后把得到的值反过来即可;
  4. 若 k 小于长度的一半,那么上一行 k 所在位置的值也为当前行所在位置的值。

AC 代码

/**
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var kthGrammar = function(n, k) {
    if(n === 1) return 0
    var curLen = 2 ** (n - 1)
    if(k > curLen / 2) {
        var val = kthGrammar(n - 1, k - curLen / 2)
        return val === 0 ? 1 : 0
    } else {
        return kthGrammar(n - 1, k)
    }
};

结果:

  • 执行结果: 通过
  • 执行用时:56 ms, 在所有 JavaScript 提交中击败了86.67%的用户
  • 内存消耗:41 MB, 在所有 JavaScript 提交中击败了37.78%的用户
  • 通过测试用例:55 / 55

END