LeetCode 第201次周赛 1545 Find Kth Bit in Nth Binary String

1 篇文章 0 订阅
1 篇文章 0 订阅

题目描述

Given two positive integers n and k, the binary string S n S_n Sn is formed as follows:

S 1 = " 0 " S_1 = "0" S1="0"
S i = S i − 1 + " 1 " + r e v e r s e ( i n v e r t ( S i − 1 ) ) S_i = S_{i-1} + "1" + reverse(invert(S_{i-1})) Si=Si1+"1"+reverse(invert(Si1)) for i > 1
Where + denotes the concatenation operation, reverse(x) returns the reversed string x, and invert(x) inverts all the bits in x (0 changes to 1 and 1 changes to 0).

For example, the first 4 strings in the above sequence are:

S 1 = " 0 " S_1 = "0" S1="0"
S 2 = " 011 " S_2 = "011" S2="011"
S 3 = " 0111001 " S_3 = "0111001" S3="0111001"
S 4 = " 011100110110001 " S_4 = "011100110110001" S4="011100110110001"
Return the k k kth bit in S n S_n Sn. It is guaranteed that k is valid for the given n.

Example 1:

Input: n = 3, k = 1
Output: “0”
Explanation: S 3 S_3 S3 is “0111001”. The first bit is “0”.
Example 2:

Input: n = 4, k = 11
Output: “1”
Explanation: S 4 S_4 S4 is “011100110110001”. The 11th bit is “1”.
Example 3:

Input: n = 1, k = 1
Output: “0”
Example 4:

Input: n = 2, k = 3
Output: “1”

Constraints:

1 <= n <= 20
1 <= k <= 2n - 1

思路

8月8日周赛第二题,根据题目描述,后一步是前一步对称扩展来的。对称中心是一个"1",两边完全对称,只不过右侧做了01反转。题目数据量只有20,从题目描述中我们知道下一项的长度是当前长度的2倍再加上对称中心的那个"1"即: l e n ( S n ) = 2 ∗ l e n ( S n − 1 ) + 1 len(S_n) = 2*len(S_{n-1})+1 len(Sn)=2len(Sn1)+1,直觉上每次都翻倍并且加1,是指数级别增长(后面我们证明)。那 S 20 S_{20} S20也就是 2 20 2^{20} 220数量级,约100万,通过暴力构造也是可以通过的。

这里简单证明一下长度是指数增长的

观察样例中给出的前4项目,长度分别是1, 3, 7, 15,大胆推测一下第n项的长度是 2 n − 1 2^n-1 2n1
证明:
数学归纳法:
S 1 = " 0 " S_1="0" S1="0"得出 l e n ( S 1 ) = 1 = 2 1 − 1 len(S_1)=1=2^1-1 len(S1)=1=211符合结论
假设 l e n ( S k ) = 2 k − 1 len(S_k)=2^k-1 len(Sk)=2k1
那么 l e n ( S k + 1 ) = 2 ∗ l e n ( S k ) + 1 = 2 ∗ ( 2 k − 1 ) + 1 = 2 k + 1 − 1 len(S_{k+1})=2*len(S_k)+1=2*(2^k-1)+1=2^{k+1}-1 len(Sk+1)=2len(Sk)+1=2(2k1)+1=2k+11符合结论,证毕
我们还能顺便得出下面这个弱智结论

  • l e n ( S n ) len(S_n) len(Sn)一定是个奇数,这个结论也没什么用。。。

利用构造对称性

假设 S n − 1 = x 1 x 2 x 1 x 3 x 4 x 5 x 6 x 7 S_{n-1}=x_1x_2x_1x_3x_4x_5x_6x_7 Sn1=x1x2x1x3x4x5x6x7
S n = x 1 x 2 x 1 x 3 x 4 x 5 x 6 x 7 1 y 7 y 6 y 5 y 4 y 3 y 2 y 1 S_{n}=x_1x_2x_1x_3x_4x_5x_6x_7\boldsymbol{1}y_7y_6y_5y_4y_3y_2y_1 Sn=x1x2x1x3x4x5x6x71y7y6y5y4y3y2y1
其中 y i = i n v e r s e ( x i ) y_i=inverse(x_i) yi=inverse(xi)
现在我们要找 S n S_n Sn的第k个字符,我们就要看k落在哪里了

  • k落在中间那个1上,那不好意思了,直接输出1
  • k落在左半区(中间那个1的左边),根据构造规则,左半区完全是从 S n − 1 S_{n-1} Sn1抄来的,所以就相当于在 S n − 1 S_{n-1} Sn1中找到第k个。例如k = 5,求 S n S_n Sn的第5个和求 S n − 1 S_{n-1} Sn1的第5个没有任何不同。
  • k落在右半边(中间那个1的右边),根据对称性,我们可以求出它在左半边对称位置的字符,然后再根据反转规则进行取反就可以得出我们要求的位置了。比如我们要求 y 2 y_2 y2,可以先求出 x 2 x_2 x2然后做个取反操作。为什么总是要先转换到左半边去求呢?因为左半边都是抄来的呀,完全照抄前一项的内容,改都没改。这么一来我们就相当于把问题推个了前一项,要知道前一项的长度可是短了很多。

代码

class Solution {
public:
    char findKthBit(int n, int k) {
        if ( n == 1 ) return '0'; //base case S_1 = “0”
        int len = (1 << n) - 1; //我们前面证明过的指数长度结论
        int m = len / 2 + 1; //中间那个1的位置(1 indexed)
        if ( k == m ) return '1'; //k落在中间那个1
        else if ( k < m ) return findKthBit(n - 1, k);//k落在左半边
        else return findKthBit(n - 1, len + 1 - k) ^ 1;//k落在右半边
    }
};

对称位置的计算问题

这里解释一下代码最后一行的那个len + 1 - k是怎么算出来的。并且通过这道题回顾一下求对称位置的方法
原理:用头尾index的和守恒
举例:一个数组,头的位置是h,尾的位置是t,求x的对称位置
假设结果是y
h + t = x + y h + t=x+y h+t=x+y
得到 y = h + t − x y=h+t-x y=h+tx,对于这道题目,h就是1,t就是len,x是k
这个方法同样适用于求某一段的对称性,h和t并不一定非得是字符串的首尾,可以是任意两个点。

代码最后一步的异或操作

char(‘0’)^1 = char(‘1’)
char(‘1’)^1 = char(‘0’)’
'0’的ASCII值是0x30,'1’是0x31,刚好是最后一个bit不一样,异或1刚好能反转最后一个bit

复杂度分析

时间o(n)
空间o(n)递归空间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值