咨询N个有序(值,计数)元组列表合并求总计数的高效方案
高效合并有序计数列表的最优方案
既然所有输入列表都是按val字段字典序排序的,多路归并算法就是比你提到的两种方法更高效的实现机制,完美适配这个场景。
核心思路
利用输入有序的特性,用优先队列(堆)维护每个列表当前待处理的元素指针:
- 先把所有非空列表的第一个元素(连同该列表的当前索引)加入最小堆,堆的排序依据是
val的字典序。 - 每次从堆顶取出
val最小的元素,然后遍历堆中所有相同val的元素,累加它们的count_of_val,得到该val的总计数。 - 把每个贡献了当前
val的列表的指针后移一位,如果该列表还有后续元素,就将新的元素重新加入堆。 - 重复步骤2-3,直到堆为空,最后按顺序输出所有累加后的元组。
这个方法的时间复杂度是O(M log N),其中M是所有列表的总元素数,N是输入列表的数量。相比逐个合并的O(M*N)复杂度,效率提升非常明显;也比转字典再排序的O(M + K log K)(K为不同val的数量)更优,尤其是当不同val的数量接近总元素数时。
Python 示例实现
import heapq def merge_sorted_count_lists(lists): heap = [] # 初始化堆:加入每个非空列表的第一个元素,记录列表索引和元素索引 for idx, lst in enumerate(lists): if lst: val, cnt = lst[0] heapq.heappush(heap, (val, cnt, idx, 0)) result = [] while heap: current_val, total_cnt, lst_idx, elem_idx = heapq.heappop(heap) # 检查堆中是否还有相同val的元素,一并累加 while heap and heap[0][0] == current_val: _, cnt, l_idx, e_idx = heapq.heappop(heap) total_cnt += cnt # 把当前列表的下一个元素放回堆(如果有) if e_idx + 1 < len(lists[l_idx]): next_val, next_cnt = lists[l_idx][e_idx + 1] heapq.heappush(heap, (next_val, next_cnt, l_idx, e_idx + 1)) # 处理当前列表的下一个元素(如果有) if elem_idx + 1 < len(lists[lst_idx]): next_val, next_cnt = lists[lst_idx][elem_idx + 1] heapq.heappush(heap, (next_val, next_cnt, lst_idx, elem_idx + 1)) # 加入结果列表 result.append((current_val, total_cnt)) return result # 测试示例 vec1 = [("a", 10), ("b", 5)] vec2 = [("a" , 7), ("b", 10), ("c", 2)] vec3 = [("d", 2)] vec4 = [] print(merge_sorted_count_lists([vec1, vec2, vec3, vec4])) # 输出:[('a', 17), ('b', 15), ('c', 2), ('d', 2)]
对比其他方案
- 逐个合并列表:每次合并两个有序列表的时间是O(k)(k为两列表总长度),N个列表合并的总时间复杂度是O(M*N),当N较大时效率极低。
- 转字典统计再排序:虽然实现简单,但需要先遍历所有元素存入字典(O(M)),再提取键值对排序(O(K log K))。如果不同
val的数量K接近总元素数M,排序的开销会很大,而且额外占用字典的存储空间。
多路归并充分利用了输入有序的前置条件,在时间和空间效率上都是最优选择。
内容的提问来源于stack exchange,提问作者NiRvanA
相关产品推荐
相关产品推荐

