LeetCode专项练习之双堆(Two Heaps)笔记

本文记录了作者在LeetCode上进行双堆专项练习的心得体会,包括如何使用堆解决Find Median from Data Stream、Sliding Window Median和IPO等难题。通过底层实现堆,作者阐述了如何利用大顶堆和小顶堆寻找中位数,并总结了双堆在解决优先队列、计划安排和最大/最小值查找等问题时的应用。
摘要由CSDN通过智能技术生成

本文是根据穷码农的LeetCode刷题建议而进行专项练习时记录的心得。

这次的题虽然只有三道,但都是Hard模式,花费了我很多时间。主要是自己以前从来没用过”堆“这个数据结构,导致自己需要相当一部分时间去从底层了解并实现它。做题时,自己也有很多思路没能想到,只能先参考大佬们的解题笔记。

不过,在自己了解了堆的特性后,觉得它理解起来并不困难,都是基于列表的一系列操作(优先队列)而实现的。这个专题之所以叫”双堆“,也是因为一般使用堆得同时用到”大顶堆“和”小顶堆“这两个概念,尤其是涉及到求中间值一类题型的时候。关于堆的具体实现,我参考了以下这篇文章:

【算法日积月累】9-堆与优先队列 | 算法与数据结构、机器学习、深度学习​

下面是我从底层实现堆的代码片段:

"""
    The implementation of data structure 'heap'(max and min) through "priority queue".
    Reference: https://www.liwei.party/2019/01/10/algorithms-and-data-structures/priority-queue/
"""
class MaxHeap:
    def __init__(self, capability):
        """
        Initiate the queue.
        Note: because the heap behaves like a tree, we use a list to "record" this tree. In addition, the first
        element starts with index 1, not 0.
        :return:
        """
        # define how many elements it can contain
        self.capability = capability
        # define the list to store data (with pre-defined space). '+1': because index starts with 1
        self.data = [None for _ in range(capability + 1)]
        # define the number of elemente
        self._count = 0

    def get_size(self) -> int:
        """
        get the size of the heap
        :return:
        """
        return self._count

    def set_size(self, size):
        """
        set the size of the heap
        :return:
        """
        self._count = size

    def is_empty(self) -> bool:
        """
        determine whether it is empty
        :return:
        """
        return self._count == 0

    def insert(self, num):
        """
        insert new data to heap
        :param num: the new element
        :return:
        """
        if self._count == self.capability:
            raise Exception("Heap reaches the limitation.")

        # insert the element to the tail first
        self._count += 1
        self.data[self._count] = num

        # see if it can be moved up
        self.shift_up(self._count)

    def shift_up(self, itemPos):
        """
        'swim' the element to higher place if it is larger than others
        :param numPos: the index of the element
        :return:
        """
        try:
            target = self.data[itemPos]

            # father: itemPos // 2
            while itemPos > 1 and self.data[itemPos // 2] < target:
                self.data[itemPos] = self.data[itemPos // 2]
                itemPos //= 2
            self.data[itemPos] = target

        except TypeError:
            print(TypeError)
            return

    def shift_down(self, itemPos):
        """
        'sink' the element to lower place if it is smaller than others
        method: as long as the 'tree' has children, it will keep replacing.
        :param numPos: the index of the element
        :return:
        """
        try:
            target = self.data[itemPos]

            # children (left): itemPos * 2
            # children (right): itemPos * 2 + 1
            while itemPos * 2 <= self._count:
                children = itemPos * 2
                # attention to the next half: left children and right children needs to be compared
                if children + 1 <= self._count and self.data[children + 1] > self.data[children]:
                    children = children + 1

                # attention: check the false condition first. If the children is smaller than target,
                # no need to keep looping (cannot write to another format —— 'itemPos' will keep changing)
                if self.data[children] <= target:
                    break

                self.data[itemPos] = self
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值