携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情
第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);
}
}