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

113 阅读4分钟

这是一篇菜鸟的题目解析~~

问题描述

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

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

测试样例

样例1:

输入:n = 10,k = 3
输出:6

样例2:

输入:n = 20,k = 5
输出:12

样例3:

输入:n = 100,k = 4
输出:10

问题理解

在给定的数组范围内容找到连续的自然数,让这些数的乘积最多包含k个不同的素因子,目标是找到可以取得连续自然数的最大长度。

首先,需要一个数据结构来存储当前窗口内所有数的素因子。其次,可以使用滑动窗口技术来动态地调整窗口的大小,以确保窗口内的素因子数量不超过k。

滑动窗口算法

处理数组或字符串的有效技术,主要用于寻找满足特定条件的子数组或子字符串,核心是通过维护一个动态的窗口,逐步扩大或缩小窗口的范围,以达到所需的条件。

原理

  1. 初始化指针:通常使用两个指针(左指针和右指针)来表示当前的窗口。左指针指向窗口的起始位置,右指针指向窗口的结束位置。
  2. 扩展窗口:通过移动右指针,逐步扩大窗口,加入新的元素。每次移动右指针后,检查当前窗口是否满足目标条件(例如,字符计数、元素总和等)。
  3. 收缩窗口:一旦窗口满足条件,就可以尝试移动左指针来收缩窗口,查看在保持条件满足的前提下,窗口的最小大小。此时需要更新相关的状态(如字符计数)。
  4. 记录结果:在每次满足条件时,记录当前窗口的大小或其他相关信息,以便在结束时得到最终结果。
  5. 结束条件:通常当右指针遍历完输入数据后,算法结束。

滑动窗口的优点在于其时间复杂度通常较低(通常为 O(n)),因为每个指针最多只遍历一次数据。这个算法特别适合于处理“最小子数组”、“包含所有字符的最小窗口”等问题。

解题

首先定义一个prime_factors函数,用于计算并返回数字x的所有素因子。

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

初始化空集合factors用以存储x的素因子,并定义变量d表示从最小的素数开始,通过两层while循环寻找符合条件的数。如果x在经过循环后仍然大于1,则说明其本身是一个素数,将其添加到factors的集合中。

其次,在solution函数中使用滑动窗口算法,确保窗口内的素因子数量不超过 k

def solution(n: int, k: int) -> int:
    left = 1
    max_length = 0
    current_factors = set()

    for right in range(1, n + 1):
        # 获取当前数的素因子
        current_factors.update(prime_factors(right))
        
        while len(current_factors) > k:
            current_factors.difference_update(prime_factors(left))
            left += 1
        
        max_length = max(max_length, right - left + 1)

    return max_length

上述代码首先初始化left为1,表示窗口的左边界,定义max_length为0,用于记录最大窗口长度。同时,定义current_factors为一个空集合,用于存储当前窗口内的素因子。

使用for right in range(1, n + 1)循环遍历[1, n]范围内的所有数。对于每个数right,计算其素因子并将其添加到current_factors集合中。

如果current_factors中的素因子数量超过k,则进入while循环。从current_factors中移除left所指数的素因子,并且将 left 向右移动一位,缩小窗口。

在每次调整窗口后,都计算当前窗口的长度right - left + 1,并更新max_length,最后返回max_length,即为答案。