[路飞]_一起刷leetcode 779. 第K个语法符号

大家好,我是挨打的阿木木,爱好算法的前端摸鱼老。最近会频繁给大家分享我刷算法题过程中的思路和心得。如果你也是想提高逼格的摸鱼老,欢迎关注我,一起学习。

题目

779. 第K个语法符号

在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为011替换为10

给定行数 N 和序数 K,返回第 N 行中第 K个字符。(K从1开始)


例子:

输入: N = 1, K = 1
输出: 0

输入: N = 2, K = 1
输出: 0

输入: N = 2, K = 2
输出: 1

输入: N = 4, K = 5
输出: 1

解释:
第一行: 0
第二行: 01
第三行: 0110
第四行: 01101001
复制代码


注意:

  1. N 的范围 [1, 30].
  2. K 的范围 [1, 2^(N-1)].

思路

  1. 写一个变化的方法,每一轮把0替换成01,1替换为10;
  2. 经过一轮循环,做替换后存储最终的字符串为result;
  3. result的第[k-1]项就是我们要找的值了。

实现

/**
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var kthGrammar = function(n, k) {
    let result = "0";
    while (n > 1) {
        result = replaceNumber(result);
        n--;
    }

    return result[k - 1];
};

// 替换当前值
function replaceNumber(str) {
    let arr = str.split("");

    return arr.reduce((total, cur) => {
        total += cur === "0" ? "01" : "10";
        return total;
    }, "");
}
复制代码

结果

image.png

空间溢出了,说明这道题目拒绝我们使用暴力解法,那么我们需要找规律。

找规律

我们可以直接看前几轮的输出,会发现一个有趣的规律:

image.png

通过观察发现当前行的值等于上一行的值 + 上一行的值做取反(即把上一轮的0换成1,1换成0)操作;那么我们可以把这道题目转换为递归问题:我们可以把当前的整个字符串切割,如果当前行的值在左半截,那么它等于上一轮的值,如果它在右半截,那么它等于上一轮的值取反,这样子一层层往上找即可。

/**
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var kthGrammar = function(n, k) {
    // 边界
    if (n === 1) return 0;

    // 先算出当前总长度, 从1开始每一轮翻两倍
    let len = Math.pow(2, n - 1);

    // 如果k在左边的一半,直接取值,如果在右边则取反
    if (k > len / 2) {
        return Number(!kthGrammar(n - 1, k - len / 2));
    } else {
        return kthGrammar(n - 1, k);
    }
};
复制代码

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。

Guess you like

Origin juejin.im/post/7040007612447850527