leetcode 第K个语法符号

73 阅读1分钟

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

第K个语法符号

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

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

提示:

  • 1 <= n <= 30
  • 1 <= k <= 2^n-1

思路

题目要求我们去找出第n行的第k个字符,其实这里的n是废物,没用的,只不过相对于给你你一点提示作用罢了

首先,我们明确一下这道题的变换规律:

  • 0替换为011替换为10

然后,我们来尝试着推导一下规律如何:

00101100110100101101001100101100 \\ 01 \\ 0110 \\ 01101001 \\ 0110100110010110 \\

感觉在直观上好像没有什么规律可言,但,其实是有规律的,我们把数列分为两部分来看待:

对于0110100110010110 0110100110010110

第一部分 0110100101101001 第二部分 1001011010010110

那么,此时,规律就出来了,第二部分和第一部分恰好是相反的存在。 每一行的后半部分正好为前半部分的“翻转”:前半部分是 0 后半部分变为 1,前半部分是 1,后半部分变为 0。

那么,我们就可以明确做法了,

首先,对于一个数,当前在第k位,有两种处理情况

  • 若是 k>2n1k > 2^{n-1},则表示,当前的k在 第二部分,此时把k映射到第一部分对于的位置去。就是 k2n1k - 2^{n-1},然后值是第k个位置的翻转值
  • 若是 k2n1k \leq 2^{n-1},则表示,当然的k在第一部分,此时k就是k位

依次循环,知道n为0时,k为1,此时,第一位是0,我们记录到了多少个翻转值,我们就知道了我们的第k位的值是多少了。

总体时间复杂度为O(n)O(n)或者O(logk)O(logk)的一个做法

代码

impl Solution {
    pub fn kth_grammar(n: i32, k: i32) -> i32 {
        let mut cnt = 0;
        let (mut n, mut k) = (n-1, k);
        while n > 0 {
            if k > (1 << (n-1)) {
                cnt += 1;
                k -= (1 << (n-1));
            }
            n -= 1;
        }
        
        if cnt % 2 == 0 {
            0
        } else {
            1
        }
    }
}