📅  最后修改于: 2023-12-03 14:58:27.576000             🧑  作者: Mango
给定一个大小为$n$的数组$a$,找到所有大小为$k$的子数组中最大值的最小值。具体地,对于每个子数组$a_{i}\ldots a_{i+k-1}$,输出其中的最大值的最小值。
例如,给定数组$a={10, 20, 30, 50, 10, 70, 30}$,$k=3$,则输出为$20, 30, 50, 50, 30$。
编写一个函数find_minimum_max(a:List[int],k:int)->List[int]
来解决上述问题。注意:只有元素数量大于或等于$k$的子数组才需要考虑。
输入:
a=[10, 20, 30, 50, 10, 70, 30]
k=3
find_minimum_max(a,k)
输出:
[20, 30, 50, 50, 30]
该问题可以使用二分搜索和单调队列来解决。
对于二分搜索解法,我们可以进行二分搜索答案x,并检查$a$中是否存在一个大小为$k$和最大值不小于$x$的子数组。为了检查这个条件,我们可以扫描$a$,并使用单调队列来找到最大值。具体地,我们维护一个下标递增的单调递减队列$q$,其中$q$存储了$a$中的下标,并且对于任意$i<j$,如果$a_i<a_j$,则$i$先于$j$被从$q$中弹出。这保证了$q$中的所有元素在$a$中的值都不小于其前面的元素。每当队列$q$达到大小$k$时,我们记录$q[0]$处的元素,然后弹出队首元素。
在遍历过程中,我们只需要检查最后得到的最小值是否大于等于$x$即可。
时间复杂度为$O(n\log w)$,其中$w$是$a$中的最大值和最小值之差。
from typing import List
def find_minimum_max(a:List[int],k:int)->List[int]:
def check(x:int)->bool:
q=[]
for i in range(n):
while q and q[0]<i-k+1:
q.pop(0)
while q and a[q[-1]]>a[i]:
q.pop()
q.append(i)
if i>=k-1 and a[q[0]]>=x:
return True
return False
n=len(a)
l,r=0,max(a)
while l<r:
mid=(l+r+1)//2
if check(mid):
l=mid
else:
r=mid-1
ans=[]
q=[]
for i in range(n):
while q and q[0]<i-k+1:
q.pop(0)
while q and a[q[-1]]>a[i]:
q.pop()
q.append(i)
if i>=k-1 and a[q[0]]>=l:
ans.append(a[q[0]])
return ans