1545. 找出第 N 个二进制字符串中的第 K 位

目录

LeetCode 1545 | 找出递归构造二进制字符串的第 k 位字符

题目描述

解题分析

字符串长度规律

结构拆分和定位

计算 reverse(invert(Sₙ₋₁)) 中对应字符的位置

解题方法

代码实现(Python)

示例说明

复杂度分析

总结


LeetCode 1545 | 找出递归构造二进制字符串的第 k 位字符

题目描述

给定两个正整数 nk,定义一个二进制字符串序列 {S_i} 如下:

  • S₁ = "0"
  • 对于 i > 1,Sᵢ = Sᵢ₋₁ + "1" + reverse(invert(Sᵢ₋₁))

其中:

  • + 表示字符串拼接
  • reverse(x) 表示字符串 x 反转
  • invert(x) 表示将字符串 x 中的每一位 0 变成 1,1 变成 0

例如,序列的前 4 项为:

S1 = "0"
S2 = "011"
S3 = "0111001"
S4 = "011100110110001"

题目要求返回字符串 Sₙ 的第 k 位字符(1-indexed)。保证 k 一定在 Sₙ 长度范围内。


解题分析

这是一个递归定义的字符串问题,我们想直接求出 Sₙ 的第 k 位,而不需要完整构造整个字符串(长度随 n 指数增长,效率极低)。

字符串长度规律

观察 Sₙ 的长度:

  • |S₁| = 1
  • |S₂| = |S₁| + 1 + |S₁| = 3
  • |S₃| = |S₂| + 1 + |S₂| = 7
  • |S₄| = |S₃| + 1 + |S₃| = 15

长度满足:

Lₙ = 2 * Lₙ₋₁ + 1
L₁ = 1

推导得:

Lₙ = 2^n - 1

结构拆分和定位

Sₙ 的结构:

Sₙ = Sₙ₋₁ + "1" + reverse(invert(Sₙ₋₁))
长度 Lₙ = 2 * Lₙ₋₁ + 1

考虑第 k 位(1-indexed)的位置:

  • 如果 k ≤ Lₙ₋₁,那么第 k 位是 Sₙ₋₁ 的第 k 位。
  • 如果 k == Lₙ₋₁ + 1,那么第 k 位是中间的 '1'。
  • 如果 k > Lₙ₋₁ + 1,则第 k 位位于 reverse(invert(Sₙ₋₁)) 中。

计算 reverse(invert(Sₙ₋₁)) 中对应字符的位置

reverse(invert(Sₙ₋₁)) 的长度也是 Lₙ₋₁。

设:

pos = k - (Lₙ₋₁ + 1)

表示第 k 位在 reverse(invert(Sₙ₋₁)) 中的位置(从左到右)。

因为该部分是反转的,即第 pos 位对应 Sₙ₋₁ 的第:

mirror_pos = Lₙ₋₁ - pos + 1

位。

同时,由于是 invert 操作,需要将该位取反:

  • 如果 Sₙ₋₁[mirror_pos] 是 '0',结果是 '1';
  • 如果是 '1',结果是 '0'。

解题方法

通过以上分析,我们可以用递归来解决问题。

伪代码逻辑:

def get_char(n, k):
    if n == 1:
        return '0'
    length = 2^n - 1
    left_len = (length - 1) // 2

    if k <= left_len:
        return get_char(n - 1, k)
    elif k == left_len + 1:
        return '1'
    else:
        pos = k - left_len - 1
        mirror_pos = left_len - pos + 1
        c = get_char(n - 1, mirror_pos)
        return invert(c)

代码实现(Python)

class Solution:
    def findKthBit(self, n: int, k: int) -> str:
        if n == 1:
            return '0'
        length = (1 << n) - 1  # 2^n - 1
        left_len = (length - 1) // 2

        if k <= left_len:
            return self.findKthBit(n - 1, k)
        elif k == left_len + 1:
            return '1'
        else:
            pos = k - left_len - 1
            mirror_pos = left_len - pos + 1
            c = self.findKthBit(n - 1, mirror_pos)
            return '1' if c == '0' else '0'

示例说明

以 n=4, k=11 为例,求 S4 的第 11 位字符。

  • S4 长度为 15,left_len = (15-1)//2 = 7
  • k=11 > 7+1=8,说明第 11 位在 reverse(invert(S3)) 部分
  • pos = 11 - 8 = 3
  • mirror_pos = 7 - 3 + 1 = 5
  • 查找 S3 的第 5 位

递归继续:

  • S3 长度为 7,left_len=3
  • k=5 > 3+1=4,位于 reverse(invert(S2))
  • pos=5-4=1
  • mirror_pos=3-1+1=3
  • 查找 S2 的第 3 位

递归继续:

  • S2 长度为 3,left_len=1
  • k=3 > 1+1=2,位于 reverse(invert(S1))
  • pos=3-2=1
  • mirror_pos=1-1+1=1
  • 查找 S1 的第 1 位,结果为 '0'

取反得到 '1',一路返回,最终结果为 '1'。


复杂度分析

  • 时间复杂度:O(n),递归深度最多为 n,且每层只调用一次。
  • 空间复杂度:O(n),递归栈深度。

相比于直接构造字符串(长度随 n 指数增长),递归定位第 k 位的方法极大地节省了时间和空间。


总结

  • 本题核心在于理解字符串的递归定义和结构拆分。
  • 利用长度规律和字符串的对称反转性质,实现了对第 k 位的快速定位。
  • 递归实现简洁高效,避免了巨大的字符串拼接和存储开销。
  • 这类题目适合训练递归思维和对字符串结构的分析能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值