是的,这是可能的!我已经修改了您的示例代码以实现此功能。
我的答案假设您的问题是关于算法的——如果您想要使用set
的最快运行代码,请参阅其他答案。
这将保持O(n log(k))
时间复杂度:从if lowest != elem or ary != times_seen:
到unbench_all = False
之间的所有代码都是O(log(k))
。主循环内有一个嵌套循环(for unbenched in range(times_seen):
),但这仅运行times_seen
次,并且times_seen
最初为0,在每次运行此内部循环后重置为0,并且每次主循环迭代只能增加一次,因此内部循环无法总共执行更多的迭代比主循环。因此,由于内部循环内的代码是O(log(k))
,并且运行的次数最多与外部循环一样多,而外部循环是O(log(k)),并且运行n次,该算法是O(n log(k))
。
这个算法依赖于Python中元组的比较方式。它比较元组的第一项,如果它们相等,则比较第二项(即(x, a)<(x, b)
当且仅当a<b
时为true)。
在这个算法中,与问题中示例代码不同的是,当从堆中弹出一个项目时,它不一定会在同一次迭代中再次推回。由于我们需要检查所有子列表是否包含相同的数字,因此在从堆中弹出数字后,它的子列表就被我称为"加入队列",意味着它不会被再次添加到堆中了。这是因为我们需要检查其他子列表是否包含相同的项,所以现在不需要添加这个子列表的下一个项目。
如果一个数字确实存在于所有子列表中,那么堆将看起来像[(2,0),(2,1),(2,2),(2,3)]
,所有元组的第一个元素都相同,所以heappop
将选择具有最低子列表索引的索引0,这意味着首先弹出索引0并增加times_seen
到1,然后弹出索引1并增加times_seen
到2——如果ary
不等于times_seen
,则该数字不在所有子列表的交集中。这导致条件if lowest != elem or ary != times_seen:
,它决定了一个数字何时不应该在结果中。这个if
语句的else
分支是为仍然可能出现在结果中的情况而设计的。
unbench_all
布尔值用于从工作台中移除所有子列表 - 这可能是因为以下原因:
- 当前的数字已知不在子列表的交集中
- 已知它在子列表的交集中
当 unbench_all
为 True
时,被移除的所有子列表将重新添加到堆中。已知这些子列表的索引范围为 range(times_seen)
,因为算法仅在它们拥有相同数字时才从堆中移除条目,所以它们必须按照索引顺序连续从索引 0 开始移除,并且其中必须有 times_seen
个。这意味着我们不需要存储被禁用的子列表的索引,只需存储被禁用的子列表数量即可。
import heapq
def mergeArys(srtd_arys):
heap = []
srtd_iters = [iter(x) for x in srtd_arys]
for idx, it in enumerate(srtd_iters):
elem = next(it, None)
if elem:
heapq.heappush(heap, (elem, idx))
res = []
times_seen = 0
lowest = heap[0][0] if heap else None
while heap:
elem, ary = heap[0]
unbench_all = True
if lowest != elem or ary != times_seen:
if lowest == elem:
heapq.heappop(heap)
it = srtd_iters[ary]
nxt = next(it, None)
if nxt:
heapq.heappush(heap, (nxt, ary))
else:
heapq.heappop(heap)
times_seen += 1
if times_seen == len(srtd_arys):
res.append(elem)
else:
unbench_all = False
if unbench_all:
for unbenched in range(times_seen):
unbenched_it = srtd_iters[unbenched]
nxt = next(unbenched_it, None)
if nxt:
heapq.heappush(heap, (nxt, unbenched))
times_seen = 0
if heap:
lowest = heap[0][0]
return res
if __name__ == '__main__':
a1 = [[1, 3, 5, 7], [1, 1, 3, 5, 7], [1, 4, 7, 9]]
a2 = [[1, 1], [1, 1, 2, 2, 3]]
for arys in [a1, a2]:
print(mergeArys(arys))
如果你愿意,可以写出一个等效的算法,如下所示:
def mergeArys(srtd_arys):
heap = []
srtd_iters = [iter(x) for x in srtd_arys]
for idx, it in enumerate(srtd_iters):
elem = next(it, None)
if elem:
heapq.heappush(heap, (elem, idx))
res = []
while heap:
elem, ary = heap[0]
lowest = elem
keep_elem = True
for i in range(len(srtd_arys)):
elem, ary = heap[0]
if lowest != elem or ary != i:
if ary != i:
heapq.heappop(heap)
it = srtd_iters[ary]
nxt = next(it, None)
if nxt:
heapq.heappush(heap, (nxt, ary))
keep_elem = False
i -= 1
break
heapq.heappop(heap)
if keep_elem:
res.append(elem)
for unbenched in range(i+1):
unbenched_it = srtd_iters[unbenched]
nxt = next(unbenched_it, None)
if nxt:
heapq.heappush(heap, (nxt, unbenched))
if len(heap) < len(srtd_arys):
heap = []
return res
k
个数组的交集中出现的元素必须至少连续出现k
次,那么仍然可以应用优先队列方法。如何有效地确定每个数组中已经看到了>=k
个连续元素是留给读者自己思考的问题。 - wLui155[0, 127]
范围内吗? - Neil[[1, 3, 3, 5, 7, 7, 9], [2, 2, 3, 3, 5, 5, 7, 7]]
中,交集是[3, 3, 5, 7, 7]
还是[3, 5, 7]
? - greybeard