python输入n个整数 输出最小的k个_线性tim中求和>=k的n个整数的最小子阵

本文讲解了一种线性时间复杂度算法,用于在给定数组中找到长度最小且和至少为k的子数组。通过deque维护起始位置并利用累积和技巧,简化了搜索过程。核心在于对起始位置的高效筛选和子数组长度的动态调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是线性时间,也是线性空间。额外的空间来自一个可以增长到线性大小的deque。(还有第二个数组来维护累计和,但可以很容易地删除它。)from collections import deque

def find_minimal_length_subarr(arr, k):

# assume k is positive

sumBefore = [0]

for x in arr: sumBefore.append(sumBefore[-1] + x)

bestStart = -1

bestEnd = len(arr)

startPoints = deque()

start = 0

for end in range(len(arr)):

totalToEnd = sumBefore[end+1]

while startPoints and totalToEnd - sumBefore[startPoints[0]] >= k: # adjust start

start = startPoints.popleft()

if totalToEnd - sumBefore[start] >= k and end-start < bestEnd-bestStart:

bestStart,bestEnd = start,end

while startPoints and totalToEnd <= sumBefore[startPoints[-1]]: # remove bad candidates

startPoints.pop()

startPoints.append(end+1) # end+1 is a new candidate

return (bestStart,bestEnd)

deque从左到右拥有一系列候选起始位置。关键不变的是deque中的位置也按“sumbore”的值递增排序。在

要了解原因,请考虑x&gt;y的两个位置x和y,并假设sumbore[x]&lt;=sumbore[y]。那么x是一个比y更好的开始位置(对于以x或更晚结束的段),所以我们再也不用考虑y了。在

进一步说明:

想象一下一个看起来像这样的天真算法:

^{pr2}$

我试图改进内部循环,只考虑某些起始点,而不是所有可能的起点。那么,我们什么时候可以从进一步考虑中排除某个特定的起点呢?有两种情况。考虑两个起点S0和S1,其中S0位于S1的左侧。在

首先,我们可以消除S0,如果我们发现S1开始了一个合格的段(也就是说,一个段的总和至少为k)。这就是第一个while循环的作用,其中start是S0,startPoints[0]是S1。即使我们找到了一些从S0开始的符合条件的段,它也会比我们已经找到的从S1开始的段长。在

第二,如果从S0到S1-1的元素之和为&lt;=0(或者,如果S0之前的元素之和=S1之前的元素之和,则等价地)我们可以消除S0。这是第二个while循环的作用,其中S0是startPoints[-1],S1是end+1。将元素从S0修剪到S1-1总是有意义的(对于S1或更高的端点),因为这样可以使线段变短而不减少其和。在

实际上,还有第三种情况,我们可以消除S0:当S0到终点的距离大于到目前为止找到的最短线段的长度。我没有实施这个案例,因为它不需要。在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值