第K个语法符号:leetcode-779

89 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情

第K个语法符号

第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

思路

方法1:依次循环

  • 一共循环 n
  • 每次将 0 替换为 o (防止重复替换)
  • 1 替换为 10
  • 最后将 o 替换为 01

问题:次数过多会导致堆栈溢出

var kthGrammar = function(n, k) {
  let str = "0"; // 第一层为0
  while(--n) {
    str = str.replace(/0/g, "o")
             .replace(/1/g, "10")
             .replace(/o/g, "01")
  }
  return str[k-1];
}

注:这种解法在leetcode上会报错(堆栈溢出)

方法2:找规律,反转值

先拿出前几层的数:

0
0 1
01 10
0110 1001
01101001 10010110
0110100110010110 1001011001101001

观察中发现,每层的前半段就是上一层,后半段就是上一层的每个值反过来(0变1、1变0)

我们可以将其分为两种情况:

  • 如果 K 在前半段,所对应的值就是上一行的第 K 个值
  • 如果 K 在后半段,可以先算出 K 相对于后半段的位置,然后找出上一行这个位置的值,将值反转
var kthGrammar = function(n, k) {
  if(n===1) return 0;
  // 计算当前层的长度
  let length = 2 ** (n - 1);
  // 如果K大于长度的一半,那么K所在位置就是后半段
  if(k > length / 2) {
    // 先得到上一行的值,位置是K相对于后半段的位置
    let pos = kthGrammar(n-1, k - length / 2); // length一定是偶数
    // 然后将值反转
    return pos === 0 ? 1 : 0;
  } else { // 否则K在前半部分
    return kthGrammar(n-1, k);
  }
}