Python程序员面试算法宝典---解题总结: 第9章 大数据 9.10 如何找出排名前500的数

本文深入探讨了在多个有序数组中寻找排名前K元素的高效算法。通过使用小顶堆和大顶堆技巧,详细解释了如何从20个各包含500个元素的数组中找出最大的500个数。文章提供了Python代码实现,展示了如何利用heapq模块解决这一经典的大数据处理问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# -*- coding: utf-8 -*-

'''
Python程序员面试算法宝典---解题总结:  第9章 大数据 9.10 如何找出排名前500的数

题目:
有20个数组,每个数组有500个元素,并且是有序排列好的,现在如何在这20 * 500
个数中找出排名前500的数?

分析:
top K问题,可以设置一个大小为500的小顶堆,
第一次先读取其中1个数组的500个数存入小顶堆,
后续读取其他数组的数字,对每个数字,如果该数字大于堆顶元素,
则删除堆顶元素,添加当前数字,所有数字遍历完,
则堆中的500个元素,就是前500大的元素。
可以用heapq实现,heapq是小顶堆。

关键:
1 书上解法
采用大顶堆加弹出方式,弹出的500个元素即为top 500
假设数组为降序排列,可以设置大顶堆(默认heap为小顶堆,
采用将数字取反放入小顶堆即可),每次弹出堆顶元素,
然后插入被弹出元素所在数组的下一个元素,调整为小顶堆即可。

2 没有想到
2.1是因为本题求的是大顶堆弹出每次堆顶,直到弹出k个,即为top K。
难点在于heapq默认是小顶堆,所以需要将数字取反,这样将取反后的
数字放入小顶堆,弹出的元素再取反实际就是最大元素。
2.2 没有想到入堆时需要存储的是一个三元组:
(元素,元素所在数组编号,元素在数组中的下标)
这样便于在弹出堆顶元素后,加入被弹出元素所在数组的下一个元素。
2.3 heapq的用法
heap = []
heapq.heappush(heap, arr)
heapq.heappop(heap)
注意堆为空的情况

参考:
Python程序员面试算法宝典
'''

import heapq

def getTopK(data, k):
    if not data or not data[0] or k <= 0:
        return
    arrayNum = len(data)
    arraySize = len(data[0])
    results = []
    # 保持一个最小堆,存放arrayNum个数组中的最小值
    heap = []
    # 初始对每个数组中第一个元素插入到小顶堆中,插入的元素是:(元素,元素所在数组编号,元素在数组中的下标)
    for i in range(0, arrayNum):
        # 注意,这里为了能使用大顶堆,对元素取反插入小顶堆
        value = (-data[i][0], i, 0)
        heapq.heappush(heap, value)
    # 开始尝试弹出
    j = 0
    while j < k:
        # 弹出堆顶元素
        try:
            arr = heapq.heappop(heap)
        except Exception:
            # 说明k超过了所有数组元素之和,这时需要直接退出
            break
        value = -arr[0]
        arrayNum = arr[1]
        index = arr[2]
        results.append(value)
        # 获取被弹出元素所在数组的下一个元素
        if index + 1 < len(data[arrayNum]):
            newArr = (-data[arrayNum][index + 1], arrayNum, index + 1)
            heapq.heappush(heap, newArr)
        else:
            # 说明有一个数组已经全部遍历完成了,则不再追加新的元素
            pass
        j += 1
    return results


def process():
    data = [[29, 17, 14, 2, 1], [19, 17, 16, 15, 6], [30, 25, 20, 14, 5]]
    k = len(data[0])
    results = getTopK(data, k)
    print results
    k = 16
    results = getTopK(data, k)
    print results


if __name__ == "__main__":
    process()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值