小C的连续自然数乘积问题解析 | 豆包MarsCode AI刷题

127 阅读4分钟

解题报告:连续自然数乘积的素因子分解问题

问题理解

本题要求在给定的范围 [1, n] 内,找到一组连续的自然数,使得这些数的乘积最多包含 k 个不同的素因子。目标是找到这组连续自然数的最大长度。

关键点

  • 连续自然数:指的是不能重复且相邻数的差为1的一组正整数,例如 [2, 3, 4, 5][5, 6, 7] 都是连续的取数。
  • 素因子:一个数的素因子是指能整除该数的素数。例如,6的素因子是2和3。
  • 最多包含 k 个不同的素因子:意味着我们需要找到一组连续的自然数,使得它们的乘积的素因子种类不超过 k

数据结构选择

为了高效地解决这个问题,我们需要选择合适的数据结构来存储和处理素因子信息。

  • 集合(Set):用于存储当前窗口内的素因子,以便快速判断素因子的种类数。
  • 字典(Dictionary):用于记录每个素因子的出现次数,以便在移动窗口时更新素因子信息。

算法步骤

  1. 初始化

    • 定义一个函数 prime_factors 用于计算一个数的所有素因子。
    • 初始化一个字典 factor_count 用于记录每个素因子的数量。
    • 初始化两个指针 leftright,分别表示当前窗口的左右边界。
    • 初始化一个变量 max_length 用于记录当前找到的最大窗口长度。
  2. 滑动窗口

    • 使用 right 指针遍历 [1, n] 范围内的所有数。
    • 对于每个数 right,计算其素因子并更新 factor_count
    • 如果当前窗口内的素因子种类数超过 k,则移动 left 指针,直到素因子种类数不超过 k
    • 在每次移动 left 指针后,更新 max_length
  3. 返回结果

    • 最终返回 max_length,即满足条件的连续自然数的最大长度。

代码详解

from collections import defaultdict

def prime_factors(x):
    factors = set()
    d = 2
    while d * d <= x:
        while (x % d) == 0:
            factors.add(d)
            x //= d
        d += 1
    if x > 1:
        factors.add(x)
    return factors

def solution(n: int, k: int) -> int:
    left = 1
    max_length = 0
    factor_count = defaultdict(int)  # 记录每个素因子的数量

    for right in range(1, n + 1):
        # 更新右边界的素因子
        factors = prime_factors(right)
        for factor in factors:
            factor_count[factor] += 1
        
        # 检查不同素因子的数量
        while len(factor_count) > k:
            # 移动左边界并更新素因子
            left_factors = prime_factors(left)
            for factor in left_factors:
                factor_count[factor] -= 1
                if factor_count[factor] == 0:
                    del factor_count[factor]
            left += 1
        
        # 计算当前窗口的长度
        max_length = max(max_length, right - left + 1)

    return max_length

if __name__ == "__main__":
    print(solution(10, 3) == 6)
    print(solution(20, 5) == 12)
    print(solution(100, 4) == 10)

代码详解

  • prime_factors 函数:用于计算一个数的所有素因子,并返回一个集合。
  • solution 函数
    • 初始化 left 指针为1,max_length 为0,factor_count 为空字典。
    • 使用 right 指针遍历 [1, n] 范围内的所有数。
    • 对于每个数 right,计算其素因子并更新 factor_count
    • 如果当前窗口内的素因子种类数超过 k,则移动 left 指针,直到素因子种类数不超过 k
    • 在每次移动 left 指针后,更新 max_length
    • 最终返回 max_length

测试样例解析

样例1

  • 输入:n = 10, k = 3
  • 输出:6
  • 解释:在 [1, 10] 范围内,连续的自然数 [2, 3, 4, 5, 6, 7] 的乘积最多包含3个不同的素因子(2, 3, 5)。

样例2

  • 输入:n = 20, k = 5
  • 输出:12
  • 解释:在 [1, 20] 范围内,连续的自然数 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 的乘积最多包含5个不同的素因子(2, 3, 5, 7, 11)。

样例3

  • 输入:n = 100, k = 4
  • 输出:10
  • 解释:在 [1, 100] 范围内,连续的自然数 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 的乘积最多包含4个不同的素因子(2, 3, 5, 7)。

总结

本题通过滑动窗口和素因子分解的方法,有效地解决了在给定范围内找到连续自然数乘积的素因子种类数不超过 k 的问题。通过合理选择数据结构和算法步骤,我们能够在较短的时间内找到满足条件的最大长度。

关键点总结

  • 滑动窗口:通过左右指针的移动,动态调整窗口内的素因子种类数。
  • 素因子分解:通过 prime_factors 函数,高效地计算每个数的素因子。
  • 字典记录:使用字典记录每个素因子的数量,便于快速更新和判断。