力扣1016高效解法:剪枝优化技巧

核心思路与优化策略

力扣 1016 题要求判断二进制字符串 S 是否包含从 1 到 N 所有整数的二进制表示作为子串。直接暴力遍历 1 到 N 并检查子串在 N 较大时会超时,因此需要利用数学性质进行剪枝优化。

关键优化点:

  1. 上限剪枝 :如果 N \> 2047(即 2\^{11}-1),直接返回 false。因为长度为 L 的二进制串最多包含 L-k+1 个长度为 k 的不同子串。对于 N 很大时,所需的二进制串长度总和远超 S 的最大长度限制(题目中 S.length \\le 1000)。具体而言,若要表示 1 到 2048,至少需要长度为 11 的二进制串 10000000000,而 S 的长度不足以容纳所有必要的组合 。
  2. 范围缩减:只需检查 \[\\lfloor N/2 \\rfloor + 1, N\] 范围内的数字。如果 S 包含了 x 的二进制串,那么它必然包含 x 右移一位(即 \\lfloor x/2 \\rfloor)的二进制串(因为 x 的二进制串去掉最后一位就是 \\lfloor x/2 \\rfloor 的二进制串)。因此,若 \[\\lfloor N/2 \\rfloor + 1, N\] 均存在,则 \[1, \\lfloor N/2 \\rfloor\] 也必然存在 。

算法实现 (Python)

以下代码实现了上述优化逻辑。首先处理 N 过大的情况,然后仅遍历 N/2 到 N 的数字,将其转换为二进制字符串并在 S中查找。

python 复制代码
class Solution:
    def queryString(self, s: str, n: int) -> bool:
        # 优化点 1: 当 N > 2047 时,由于字符串 S 长度限制 (<=1000),不可能包含所有子串
        # 2^11 = 2048,二进制长度为 11。若 N 过大,所需子串总长度超过 S 的最大可能容量
 if n > 2047:
            return False
        
        # 优化点 2: 只需检查 [n//2 + 1, n] 区间
        # 原理:如果 x 的二进制是 S 的子串,那么 x>>1 (即 x//2) 的二进制也是 S 的子串
        # 只要最大的那一半数字都在,较小的一半自然也在
        for i in range(n // 2 + 1, n + 1):
            # 将整数转换为二进制字符串 (去掉 '0b' 前缀)
            binary_rep = bin(i)[2:]
            
            # 检查是否为子串
            if binary_rep not in s:
                return False
                
        return True

复杂度分析

指标 说明
时间复杂度 O(\\min(N, K) \\cdot L),其中 K=2047 是剪枝上限,L 是二进制串平均长度。由于 N 被限制在常数范围内,实际复杂度接近 $O(L \cdot
空间复杂度 O(L),用于存储临时生成的二进制字符串,L 为 \\log_2 N。
适用场景 适用于 S 长度较小 (\\le 1000) 但 N 可能很大的情况,通过数学剪枝避免无效计算 。

示例推导

假设输入 S = "0110", N = 3:

  1. 剪枝检查:3 \\le 2047,继续。
  2. 确定范围:需检查 \[\\lfloor 3/2 \\rfloor + 1, 3\] 即 \[2, 3\]。
  3. 执行检查 :
    • i=2: 二进制为 "10"。S 中包含 "10" 吗?是的 ( 0 10 ... 这里的索引有点问题,实际上是 0110 中包含 10 吗? 0110 的子串有 01, 11, 10。是的,包含)。
    • i=3:二进制为 "11"。S 中包含 "11" 吗?是的。
  4. 结论 :所有检查通过,返回 true 。

假设输入 S = "0110", N = 4:

  1. 确定范围:需检查 \[\\lfloor 4/2 \\rfloor + 1, 4\] 即 \[3, 4\]。
  2. 执行检查 :
    • i=3: "11" 在 S 中。
    • i=4: 二进制为 "100"。S ( 0110) 中不包含 "100"。
  3. 结论 :返回 false 。

参考来源

相关推荐
xiangyun612 小时前
C++ priority_queue 底层:手撕二叉堆与 Top K 问题
c++·算法·面试·stl·1024程序员节
坤坤子吖2 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
技术小甜甜2 小时前
【Cursor】Skill 被标黄色警告,怎么改成合格的 SKILL.md
开发语言·javascript·ai编程·cursor·1024程序员节·ai agent·skills
qz_Serene2 小时前
练习算法题:双指针 -cpp
c++·算法·leetcode·1024程序员节
扶尔魔ocy3 小时前
【C++开发】从裸指针到智能指针
c++·智能指针·1024程序员节
小小龙学IT3 小时前
Python Polars 高性能数据处理引擎深度解析
开发语言·python·rust·1024程序员节
Nuanyt3 小时前
Hot 100 刷题笔记 · 数组与哈希专题(3 题)
java·笔记·算法·leetcode·哈希算法·1024程序员节
quantdash_cc3 小时前
如何利用标的信息为研究股票池补充名称和交易所信息?
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash
莫叫石榴姐3 小时前
半导体业务数仓建模: Lot、Wafer、Die、Recipe、OEE、YMS 建模要点
数据仓库·sql·面试·职场和发展·矩阵·1024程序员节