解析“疯狂整数的统计”题目 | 豆包MarsCode AI刷题

41 阅读5分钟

学习方法与心得:解析“疯狂整数的统计”题目

一、问题描述及背景

在这道题目中,我们需要统计不大于某个整数 ( N ) 的所有“疯狂整数”的数量。疯狂整数被定义为仅由数字 12 组成的整数,比如 ( 1, 2, 11, 12, 121 ) 等。简单来说,这是一个具有特定构造规则的数字集合。

这类问题看似简单,但背后涉及的数字生成和搜索策略让其更具挑战性。问题的核心在于找到一种高效的方法,既能生成这些符合条件的数字,又不会重复计算或遗漏结果。


二、解题思路分析

面对这个问题,可以分为两个关键步骤:

  1. 生成疯狂整数
    从基本单位 ( 1 ) 和 ( 2 ) 开始,通过组合生成更大的疯狂整数。这种生成方法类似于广度优先搜索(BFS),每次从当前数字扩展出两个新数字(分别添加 ( 1 ) 和 ( 2 ))。

  2. 限制条件检查
    每生成一个疯狂整数时,检查是否满足条件(即小于或等于 ( N ))。若满足,计数并继续扩展;若不满足,则直接跳过,避免无效的扩展。

结合以上两点,最优的实现方法是利用队列(Queue)。以下是具体思路:

  • 初始化队列,先放入最基本的疯狂整数 ( 1 ) 和 ( 2 );
  • 每次从队列中取出一个数字,判断是否符合条件;
  • 若符合条件,将其计入结果并继续生成更大的数字;若不符合条件,停止扩展。

这种方法的优点是避免重复计算,并且控制生成的数字规模,从而保证了算法的效率。


三、代码详解

以下是完整代码的详细解析:

from collections import deque

def solution(N: int) -> int:
    # 初始化队列,放入初始疯狂整数 1 和 2
    queue = deque(["1", "2"])
    count = 0

    # 逐一处理队列中的数字
    while queue:
        num_str = queue.popleft()  # 从队列头部取出一个字符串
        num = int(num_str)  # 转为整数

        # 如果生成的数字超过 N,停止搜索
        if num > N:
            continue

        # 计数符合条件的疯狂整数
        count += 1

        # 在当前数字后添加 '1' 和 '2',生成新数字加入队列
        queue.append(num_str + "1")
        queue.append(num_str + "2")

    return count

代码关键点说明:

  1. 队列初始化
    queue = deque(["1", "2"]):队列的初始值为两个最基本的疯狂整数 ( 1 ) 和 ( 2 )。这些是生成后续疯狂整数的“种子”。

  2. 数字生成
    queue.append(num_str + "1")queue.append(num_str + "2"):从队列中取出的每个数字都可以通过在末尾添加 ( 1 ) 或 ( 2 ) 来生成两个新数字。这种操作构成了疯狂整数的递归扩展。

  3. 条件限制
    if num > N: continue:若生成的数字超过给定的上限 ( N ),直接跳过,避免浪费计算资源。

  4. 循环终止
    队列为空时循环结束,这保证了所有可能的疯狂整数都被处理了一次且仅一次。


四、测试样例分析

通过几个具体的测试样例,可以更直观地理解算法的运行过程:

  1. 示例 1:N = 21

    • 初始队列:["1", "2"]
    • 扩展过程:
      1. 取 ( "1" ),生成 ( "11", "12" ),计数 ( 1 );
      2. 取 ( "2" ),生成 ( "21", "22" ),计数 ( 2 );
      3. 取 ( "11" ),生成 ( "111", "112" ),计数 ( 3 );
      4. 取 ( "12" ),生成 ( "121", "122" ),计数 ( 4 );
      5. 取 ( "21" ),停止扩展,计数 ( 5 )。
    • 最终结果:( 5 )。
  2. 示例 2:N = 50
    类似扩展,最终生成的疯狂整数包括 ( 1, 2, 11, 12, 21, 22 ),共计 ( 6 ) 个。

  3. 示例 3:N = 5
    只有 ( 1, 2 ) 满足条件,最终结果为 ( 2 )。


五、算法效率与优化分析

  1. 时间复杂度
    由于每个数字生成两个新数字,因此算法的时间复杂度大致为 ( O(2^d) ),其中 ( d ) 是疯狂整数的最大位数(受 ( N ) 限制)。在实际运行中,由于数字大小受到 ( N ) 的约束,复杂度可控。

  2. 空间复杂度
    使用队列存储当前待处理的数字,空间复杂度为 ( O(2^d) )。

  3. 优化方向

    • 剪枝优化:若数字过大,则立即停止扩展;
    • 多线程并行:对于大规模 ( N ),可以通过多线程加速数字生成和筛选过程。

六、个人学习心得

通过这道题目,我深刻体会到:

  1. 队列的妙用:在生成组合或层次遍历问题中,队列是一个非常高效的工具。它简化了数字扩展和条件筛选的流程。
  2. 问题的抽象化:题目表面上是统计数字,实质上是一个构造与搜索问题。理解本质后,广度优先搜索(BFS)的思路自然浮现。
  3. 编程习惯的培养:AI的解析让我更加注重代码的结构化和可读性,比如通过注释清晰表达每一步的意图。这对提升编码质量非常有帮助。

七、总结

这道“疯狂整数的统计”题目通过简单的数字生成和筛选,向我们展示了如何用高效的数据结构(队列)和搜索策略(BFS)解决实际问题。对我而言,这不仅是一次算法思维的训练,更是一种编程思想的升华。AI的详细解析和指导让我能够从更高的视角理解问题,并快速提升了解决复杂问题的能力。