给定数组arr和整数num,保证max(arr[i…j]) - min(arr[i…j]) <=num,其中max(arr[i…j])表示子数组 arr[i…j]中的最大值,min(arr[i…j])表示子数组arr[i…j]中的最小值。假定数组长为N,实现时间复杂度O(N)的解法。
0开头的有N个,1开头有N-1个,等差数列,一共有O(N
2
^2
2)个子数组。
首先暴力方法 O(N
3
^3
3)
def isValid(arr, start, end, num):
max1=max(arr[start:end+1])
min1=min(arr[start:end+1])
return max1-min1 <= num
arr = [2,3,4,2,6,2,5,1]
n = len(arr)
num = 3
res1 = 0
for start in range(n):
for end in range(start, n):
if(isValid(arr, start, end, num)):
res1 += 1
print(res1)
最优解 O(N)
一个子数组 如果[R, L]达标了,max-min<=m, 那么R…L内的子数组都达标,如果[R, L]不达标了max-min>m,那么…R, L…往外扩都不达标了。
一开始让L=0, R 往外扩,到最后一个达标的数位置X,再往下一个位置x+1就不达标了,这样就得到了 0,0-1,…0-x,共x+1个。这样位置0 开头的就判断完了。然后L来到1位置,接着看R能扩到哪个位置。直到L到最后的位置。
在扩的过程中判断子数组是否达标,用滑动窗口。
qmin = [] #窗口内的最小值
qmax = [] #窗口内的最大值
L = 0
R = 0
res2 = 0
while L<len(arr):
while R<len(arr):
while len(qmin)!=0 and arr[qmin[-1]] >= arr[R]: #更新最小值
qmin.pop()
qmin.append(R)
while len(qmax)!=0 and arr[qmax[-1]] <= arr[R]: #更新最大值
qmax.pop()
qmax.append(R)
if arr[qmax[0]] - arr[qmin[0]] > num: #如果不满足了,break,R为X+1了,满足的有R-L个
break
R += 1
res2 += R-L
if qmin[0] == L: #L要向右移动了,L位置的值要pop掉
qmin.pop(0)
if qmax[0] == L:
qmax.pop(0)
L += 1
print(res2)