这是一篇菜鸟的题目解析~~
问题描述
小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。
滑动窗口算法
处理数组或字符串的有效技术,主要用于寻找满足特定条件的子数组或子字符串,核心是通过维护一个动态的窗口,逐步扩大或缩小窗口的范围,以达到所需的条件。
原理
- 初始化指针:通常使用两个指针(左指针和右指针)来表示当前的窗口。左指针指向窗口的起始位置,右指针指向窗口的结束位置。
- 扩展窗口:通过移动右指针,逐步扩大窗口,加入新的元素。每次移动右指针后,检查当前窗口是否满足目标条件(例如,字符计数、元素总和等)。
- 收缩窗口:一旦窗口满足条件,就可以尝试移动左指针来收缩窗口,查看在保持条件满足的前提下,窗口的最小大小。此时需要更新相关的状态(如字符计数)。
- 记录结果:在每次满足条件时,记录当前窗口的大小或其他相关信息,以便在结束时得到最终结果。
- 结束条件:通常当右指针遍历完输入数据后,算法结束。
滑动窗口的优点在于其时间复杂度通常较低(通常为 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,即为答案。