我正在尝试解决Python中的以下问题
给定一个数组和一个整数k,找到每个大小为k的连续子阵列的最大值。
想法是使用双端队列。这是我的代码:
def diff_sliding_window(arr, win):
# max = -inf
Q = []
win_maxes = [] # max of each window
for i in range(win):
print(Q)
while len(Q) > 0 and arr[i] >= arr[len(Q) - 1]:
# get rid of the index of the smaller element
Q.pop() # removes last element
Q.append(i)
# print('>>', Q)
for i in range(win, len(arr)):
# win_maxes.append(arr[Q[0]])
print(arr[Q[0]])
while len(Q) > 0 and Q[0] <= i - win:
Q.pop()
while len(Q) > 0 and arr[i] >= arr[len(Q)-1]:
Q.pop(0)
Q.append(i)
# win_maxes.append(arr[Q[0]])
print(arr[Q[0]])
但我无法弄清楚测试用例的原因:
t1 = [1, 3, -1, -3, 5, 3, 6, 7]
t2 = [12, 1, 78, 90, 57, 89, 56]
我没有得到正确的结果。
更新:
我做了Matt Timmermans建议的改动,但我仍然没有得到正确的输出。适用于t2
和win = 3
78
90
90
89 <--- should be 90
89
这是我更新的代码:
from collections import deque
def diff_sliding_window(arr, win):
# max = -inf
Q = deque()
win_maxes = [] # max of each window
for i in range(win):
# print(Q)
while len(Q) > 0 and arr[i] >= arr[Q[len(Q)-1]]:
# get rid of the index of the smaller element
Q.pop() # removes last element
Q.append(i)
# print('>>', Q)
for i in range(win, len(arr)):
# win_maxes.append(arr[Q[0]])
print(arr[Q[0]])
while len(Q) > 0 and Q[0] <= i - win:
Q.pop()
while len(Q) > 0 and arr[i] >= arr[Q[len(Q)-1]]:
Q.popleft()
Q.append(i)
print(arr[Q[0]])
答案 0 :(得分:2)
看起来你正在尝试为这个问题实现O(n)算法,这比此时的其他两个答案要好。
但是,您的实施不正确。如果你说arr[i] >= arr[len(Q)-1]
,应该说arr[i] >= arr[Q[len(Q)-1]]
或arr[i] >= arr[Q[-1]]
。您还在第二个循环中交换了pop
和pop(0)
个案例。修好后,它看起来是正确的。
此外,您的算法不是O(n),因为您使用Q.pop(0)
,这需要O(k)时间。因此,您的总运行时间为O(kn)。使用Q
的双端队列将解决此问题。
这里已全部修复,并附有一些评论以显示其工作原理:
from collections import deque
def diff_sliding_window(arr, win):
if win > len(arr):
return []
win_maxes = [] # max of each window
#Q contains indexes of items in the window that are greater than
#all items to the right of them. This always includes the last item
#in the window
Q = deque()
#fill Q for initial window
for i in range(win):
#remove anything that isn't greater than the new item
while len(Q) > 0 and arr[i] >= arr[Q[-1]]:
Q.pop()
Q.append(i)
win_maxes.append(arr[Q[0]])
for i in range(win, len(arr)):
#remove indexes (at most 1, really) left of window
while len(Q) > 0 and Q[0] <= (i-win):
Q.popleft()
#remove anything that isn't greater than the new item
while len(Q) > 0 and arr[i] >= arr[Q[-1]]:
Q.pop()
Q.append(i)
win_maxes.append(arr[Q[0]])
return win_maxes
证明这是O(N):内部循环的每次迭代都会从Q中删除一个项目。因为总共只有len(arr)
添加到Q,所以最多可以len(arr)
< em>内部循环的总次迭代。
答案 1 :(得分:0)
这种方法怎么样(只需要对数据进行一次传递):
def calc(xs, k):
k_max = []
result = []
for ind, val in enumerate(xs):
# update local maxes (all are active)
for i in range(len(k_max)):
if val > k_max[i] :
k_max[i] = val
# one new sub-array starts
k_max.append(val)
if ind >= (k-1): # one sub-array ends
result.append(k_max[0])
k_max.pop(0)
return result
t1 = [1, 3, -1, -3, 5, 3, 6, 7]
t2 = [12, 1, 78, 90, 57, 89, 56]
print(calc(t1, 3))
print(calc(t2, 2))
[3, 3, 5, 5, 6, 7]
[12, 78, 90, 90, 89, 89]
答案 2 :(得分:0)
这是使用itertools
和tee
的简单解决方案:
def nwise(iterable, n):
''' Step through the iterable in groups of n '''
ts = it.tee(iterable, n)
for c, t in enumerate(ts):
next(it.islice(t, c, c), None)
return zip(*ts)
def max_slide(ns, l):
return [max(a) for a in nwise(ns, l)]
>>> max_slide([1, 3, -1, -3, 5, 3, 6, 7], 3)
[3, 3, 5, 5, 6, 7]
>>> max_slide([12, 1, 78, 90, 57, 89, 56], 3)
[78, 90, 90, 90, 89]