【路飞】第k个语法符号&&斐波那契数列

197 阅读2分钟

记录 2 道算法题

第 k 个语法符号

leetcode-cn.com/problems/k-…


n是第几行, k是第几个

0会在下一行变成01,1会在下一行变成10

    第一行: 0
    第二行: 01
    第三行: 0110
    第四行: 01101001

想知道当前第 n 行,第 k 个是多少首先要知道 n - 1 行,即上一行是 0 还是 1, 然后还要知道第 k 个是上一行分裂的数的第一位还是第二位。

假如上一行是 1,那么这一行就要分裂成 10 ,然后要考虑第 k 个是 1 还是 0,即是奇数位还是偶数位。

分成两两一组的话,第 k 个除以 2 如果是小数,则说明是下一组的第一个。如果是整数,说明是这一组的第二个。

比如 第 4 行,第 5 个。 是位于第 3 组的 10 或 01 里面。

所以 第 k 个对应的上一行是 Math.ceil(k / 2)

这种层层递进的可以通过递归来寻找,正好传入 n - 1 可以作为终点。因为找到第二行的时候,只有两种结果。

递归注意的点是, 终止条件,每一个单元的操作。

    function kthGrammar(n, k) {
        if (n === 1) {
            return 0
        }
        if (n === 2) {
            // 第二行只有 01
            if (k === 1) {
                return 0
            } else {
                return 1
            }
        }
        
        // 我们希望 kthGrammar 可以返回上一行是 1 是 0,
        // 然后根据 k 所在是奇数位还是偶数位,得到上一行的 1 或 0 分裂的对应的数
        let i = kthGrammar(n - 1, Math.ceil(k / 2))
        i = i === 1 ? [1, 0] : [0, 1]
        return k % 2 === 1 ? i[0] : i[1]
    }

其实还有一种找规律的解法。就是每一行的前一半都和上一行相等。然后后一半都是前一半的每一位相反。

所以可以判断 k 是在前一半还是后一半,如果是后一半就等于前一半相同位置的相反。等于上一行的同一位置的相反。如果到了上一行发现是上一行的后一半。则和前面相同的过程处理一遍。

又套起来了。

斐波那契数列

leetcode-cn.com/problems/fe…


f(0) = 0 f(1) = 1 f(n) = f(n - 1) + f(n - 2)

要求结果取余 1000000007

有两种解法,一种是递归,一种是循环

递归版本

    // 用 map 来减少重复计算
    const map = new Map([[0, 9], [1, 1]])
    function lib(n) {
        if (map.has(n)) {
            return map.get(n)
        } else {
            const c = (lib(n - 1) + lib(n - 2)) % 1000000007
            map.set(n , c)
            return c
        }
    }

循环版本

    function fib(n) {
      if (n === 0) {
        return 0
      }
      if (n === 1) {
        return 1
      }

      let a = 0,b = 1
      // 0 1 1 2 3 5
      // a b c
      // c 是当前的位置。 a 和 b 等价于 n-1 和 n-2
      for (let i = 2; i <= n+1; i++) {
        const c = (a + b) % 1000000007 /* leetcode 要求取余 */
        a = b
        b = c
      }

      return b
   }

结束