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

37 阅读3分钟

问题描述

小S在学习素数因子的分解,她希望在[1,n][1,n]的范围内,找到一些连续的自然数,这些数的乘积最多包含kk个不同的素因子。你的任务是帮助小S找到可以取的连续自然数的最大长度。

连续的自然数指的是不能重复且相邻数的差为1的一组正整数,例如 [2, 3, 4, 5] 和 [5, 6, 7] 都是连续的取数。

from collections import defaultdict
def prime_factors(num):
"""计算一个数的所有素因子"""
factors = set()
# 处理2的因子
while num % 2 == 0:
    factors.add(2)
    num //= 2
# 处理奇数因子
for i in range(3, int(num**0.5) + 1, 2):
    while num % i == 0:
        factors.add(i)
        num //= i
# 如果num是一个素数
if num > 2:
    factors.add(num)
return factors

def solution(n: int, k: int) -> int:
max_length = 0
left = 1
factor_count = defaultdict(int)
for right in range(1, n + 1):
    # 获取当前数的素因子并更新因子计数
    for factor in prime_factors(right):
        factor_count[factor] += 1
    # 当因子数量超过k时,移动左边界
    while len(factor_count) > k:
        for factor in prime_factors(left):
            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)

解题思路

  1. 素因子分解:首先,我们需要一个方法来找到任意正整数的所有素因子。素因子分解是将一个数分解为几个素数的乘积。
  2. 滑动窗口:我们使用滑动窗口技术来遍历所有可能的连续自然数序列。滑动窗口允许我们动态地增加和减少窗口的大小,同时保持窗口内的元素满足特定条件(在这个问题中是素因子的数量不超过 k)。
  3. 维护素因子计数:在滑动窗口中,我们需要维护一个计数器来记录当前窗口内所有数的素因子的出现次数。

步骤

  1. 计算素因子:定义一个函数 prime_factors 来计算一个数的所有素因子。
  2. 初始化变量:定义一个字典 factor_count 来记录素因子的出现次数,left 和 right 分别表示滑动窗口的左右边界,max_length 用于记录找到的最长序列长度。
  3. 滑动窗口遍历:使用一个循环,从 1 到 n 遍历所有自然数,每次将 right 指向的数加入窗口,并更新 factor_count
  4. 调整窗口大小:如果当前窗口内的素因子数量超过了 k,则移动左边界 left,直到窗口内的素因子数量不超过 k
  5. 更新最大长度:在每次调整窗口大小后,更新 max_length

用到的知识点

  • 素数:只有 1 和它本身两个因数的数。
  • 素因子分解:将一个数分解为几个素数的乘积。
  • 滑动窗口:一种用于数组/字符串的窗口,可以动态地增加和减少窗口的大小。
  • 哈希表(字典) :用于快速查找和更新元素。

时间空间复杂度

  • 时间复杂度:对于每个数,我们可能需要 O(√n) 的时间来找到它的素因子。在最坏的情况下,我们需要对每个数都进行素因子分解,因此总的时间复杂度是 O(n√n)。
  • 空间复杂度:我们需要一个字典来存储素因子的计数,在最坏的情况下,这个字典可能包含所有小于等于 n 的素数,因此空间复杂度是 O(√n)。