持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
第K个语法符号
我们构建了一个包含 n 行( 索引从 1 开始 )的表。首先在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。
- 例如,对于
n = 3,第1行是0,第2行是01,第3行是0110。 给定行数n和序数k,返回第n行中第k个字符。(k从索引 1 开始)
提示:
1 <= n <= 301 <= k <= 2^n-1
思路
题目要求我们去找出第n行的第k个字符,其实这里的n是废物,没用的,只不过相对于给你你一点提示作用罢了
首先,我们明确一下这道题的变换规律:
0替换为01,1替换为10
然后,我们来尝试着推导一下规律如何:
感觉在直观上好像没有什么规律可言,但,其实是有规律的,我们把数列分为两部分来看待:
对于
第一部分 第二部分
那么,此时,规律就出来了,第二部分和第一部分恰好是相反的存在。 每一行的后半部分正好为前半部分的“翻转”:前半部分是 0 后半部分变为 1,前半部分是 1,后半部分变为 0。
那么,我们就可以明确做法了,
首先,对于一个数,当前在第k位,有两种处理情况
- 若是 ,则表示,当前的k在 第二部分,此时把k映射到第一部分对于的位置去。就是 ,然后值是第k个位置的翻转值
- 若是 ,则表示,当然的k在第一部分,此时k就是k位
依次循环,知道n为0时,k为1,此时,第一位是0,我们记录到了多少个翻转值,我们就知道了我们的第k位的值是多少了。
总体时间复杂度为或者的一个做法
代码
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
}
}
}