leetcode 779. 第K个语法符号

96 阅读2分钟

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

1. 题目与解析

我们构建了一个包含 n 行( 索引从 1  开始 )的表。首先在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。

例如,对于 n = 3 ,第 1 行是 0 ,第 2 行是 01 ,第3行是 0110 。 给定行数 n 和序数 k,返回第 n 行中第 k 个字符。( k 从索引 1 开始)

输入: n = 1, k = 1

输出: 0

输入: n = 2, k = 1

输出: 0

解释: 第一行: 0 第二行: 01

输入: n = 2, k = 2

输出: 1

我们可以尝试写几行数据,看一看其中的规律:

  • 1: 0
  • 2: 01
  • 3: 0110
  • 4: 01101001
  • 5: 0110100110010110

我们以4,5行为例子来看一看:

  • [01101001]
  • [01101001][10010110]

总结规律,第i行的数字其实就是第i-1行数字本身再拼接上其每一位取反得到的数字串,我们可以根据这一点,每次将数字对折到前一部分取反,一直对折到第一位0为止。

由上述可知,其实我们需要计算的就是i对折的次数,那么有没有什么办法呢?

我们来思考每一次i向内对折数量的特点,我们以两个数字为一小组来进行区分:

`{[(1,2)(3,4)][(5,6)(7,8)]}{[(9,10)(11,12)][(13,14)(15,16)]}`

我们要做的就是通过折叠将i数字折叠到1的位置

我们可以对数字i减去其本身向下取2的n次幂的大小的数值来实现对折的操作,可以通过一个循环来判断是否得到了我们要减去的数值。

while (mod >= k) {
    mod /= 2;
} 

2. 题解

整体的解题思路如下所示:

class Solution {
    public int kthGrammar(int n, int k) {
        int ans = 0;
        int mod = (int) Math.pow(2, n-2);       
        while (k > 1) {                    
            while (mod >= k) {
                mod /= 2;
            }   
            k -= mod;        
            ans ^= 1;         
        }
        return ans;
    }
}