LeetCode703:数据流中的第k大元素 (附:优先队列的基础)

python中实现优先队列的基础知识:
相关链接:链接

常用概括:
需要引入的库:

import heapq

返回数组中前K个最大或者最小的元素:

import heapq

nums = [14, 20, 5, 28, 1, 21, 16, 22, 17, 28]
heapq.nlargest(3, nums)    # 第一个参数是返回的元素的数量
# [28, 28, 22]
heapq.nsmallest(3, nums)
# [1, 5, 14]

自己定义按照什么因素进行排列:

laptops = [
    {'name': 'ThinkPad', 'amount': 100, 'price': 91.1},
    {'name': 'Mac', 'amount': 50, 'price': 543.22},
    {'name': 'Surface', 'amount': 200, 'price': 21.09},
    {'name': 'Alienware', 'amount': 35, 'price': 31.75},
    {'name': 'Lenovo', 'amount': 45, 'price': 16.35},
    {'name': 'Huawei', 'amount': 75, 'price': 115.65}
]

cheap = heapq.nsmallest(3, laptops, key=lambda s: s['price'])
expensive = heapq.nlargest(3, laptops, key=lambda s: s['price'])

优先队列
heapq除了可以返回最大最小的K个数之外,还实现了优先队列的接口。我们可以直接调用heapq.heapify方法,输入一个数组,返回的结果是根据这个数组生成的堆(等价于优先队列)。当然也可以从零开始,直接通过调用heapq的push和pop来维护这个堆。
heapq 默认构建的是小顶堆,所以在具体的问题中,需要确定使用的是小顶堆还是大顶堆。heapq.heapqpush()需要两个参数,第一个是存储元素的数组,第二是要存储的元素,可以是一个数,也可以是一个元组(a,b),存储一个元组的时候,按照元组的第一项a进行排序。

题目描述:
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
示例:
输入:
[“KthLargest”, “add”, “add”, “add”, “add”, “add”]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:
[null, 4, 5, 5, 8, 8]
解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8

思路一:
每加入一个元素,与数组现有的第k大元素进行比较,如小于第k大,则第k 大保持不变,否则,将新加入的元素加入到数组中,进行快排返回第k大元素,在python中,可以直接利用sorted对数组进行快排,但是注意该函数的返回值是排列后的顺序,该函数不是inplace的,所以通常需要一个新的数组进行接收排序后的结果。

class KthLargest(object):

    def __init__(self, k, nums):
        """
        :type k: int
        :type nums: List[int]
        """
        self.k = k
        self.nums = nums
        print(nums)
        print(self.nums)

    def add(self, val):
        """
        :type val: int
        :rtype: int
        """
        s_nums = sorted(self.nums)
        if len(s_nums) - self.k >= 0 and val < s_nums[len(s_nums) - self.k]:
            n = len(self.nums)
            return s_nums[n - self.k]
        else:
            self.nums.append(val)
            s_nums = sorted(self.nums)
            n = len(self.nums)
            return s_nums[n-self.k]

时间复杂度为:O(N*nlogn),这种方法在立扣上容易超出时间限制。
思路二:
构建一个大小为k的小顶堆,则堆头就是第K大的元素,每次到来一个新的元素的时候,将其加入到优先队列中,然后对优先队列进行pop处理,保证队列的长度始终为k,这样最终只需要返回堆顶即可返回得到当前的第k大。(注意:这种每次都加入到堆中,然后pop到指定长度的思想是很常用的)

import heapq


class KthLargest(object):

    def __init__(self, k, nums):
        """
        :type k: int
        :type nums: List[int]
        """
        self.k = k
        self.nums = nums
        heapq.heapify(self.nums)


    def add(self, val):
        """
        :type val: int
        :rtype: int
        """
        heapq.heappush(self.nums, val)
        while len(self.nums) > self.k:
            heapq.heappop(self.nums)
        return self.nums[0]

时间复杂度:O(N*logk)。
这种数据流而非固定长度的找第k大或者小的问题,一般都是通过优先队列实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值