python中的大小堆 heapq

首先看例子:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof

解:

from heapq import *
class MedianFinder:
    def __init__(self):
        # 大小堆一半一半,中位数只要取堆顶   但是python中的堆  堆的索引位置0的值是堆中的最小值 【B | A】
        """
建立一个 小顶堆 A 和 大顶堆 B ,各保存列表的一半元素,且规定:

A 保存 较大 的一半,长度为 \frac{N}{2}( N 为偶数)或 \frac{N+1}{2} ( N 为奇数);
B 保存 较小 的一半,长度为 \frac{N}{2}( N 为偶数)或 \frac{N-1}{2} ( N 为奇数);
随后,中位数可仅根据 A, B的堆顶元素计算得到。

        """ 
        self.A = [] #小顶堆  堆顶为最小值 
        self.B = [] #大顶堆  堆顶为最大值(所以实现起来  用  负数)


    def addNum(self, num: int) -> None:
        if len(self.A)!=len(self.B):
            heappush(self.A,num)
            heappush(self.B,-heappop(self.A)) 
        else:
            heappush(self.B,-num)
            heappush(self.A,-heappop(self.B))

        

    def findMedian(self) -> float:
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2.0

heap

文档:heapq --- 堆队列算法 — Python 3.10.0 文档

  • 只能是列表
  • 能通过"<"比较  
  • 堆特性

    一个列表heap它里面的每一个元素都符合    heap[0] <= heap[2*k+1]和heap[0] <= heap[2*k+2]  ,那么这个heap就具有堆特性(python中的堆是最小堆, 也就是说堆的索引位置0的值是堆中的最小值.)

heapq.heappop(heap) 弹出索引位置0中的值

大佬:heapq.heappop(heap) 弹出索引位置0中的值 - 跟丫死磕 (weshallneversurrender.com)

heapq.heappush() 将一个对象压入堆中

大佬:python heapq.heappush() 将一个对象压入堆中 - 跟丫死磕 (weshallneversurrender.com)

 

C++中的大小堆用法解题

用库函数 priority_queue<int,vector<int>,less<int>> or priority_queue<int,vector<int>,greater<int>> 方便地实现大小堆:Priority Queue in C++ Standard Template Library (STL) - GeeksforGeeks

方法:

  • res = minHeap.pop()
  • minHeap.top()
  • minHeap.push(item)
class MedianFinder {
public:
    //  【左边 | 右边】
    // 最大堆 堆顶为最大值 存储左边一半
    priority_queue<int,vector<int>,less<int>> maxHeap;
    // 最小堆 堆顶为最小值 存储右边一半
    priority_queue<int,vector<int>,greater<int>> minHeap;
    MedianFinder() {
    }
    
    void addNum(int num) {
        if(maxHeap.size()!=minHeap.size()){
            maxHeap.push(num);
            int top_of_maxHeap = maxHeap.top();
            maxHeap.pop();
            minHeap.push(top_of_maxHeap);
        }else{
            minHeap.push(num);
            int top_of_minHeap = minHeap.top();
            minHeap.pop();
            maxHeap.push(top_of_minHeap);
        }
    }
    
    double findMedian() {
        if(maxHeap.size()!=minHeap.size()){
            return maxHeap.top()*1.0;
        }else{
            return (maxHeap.top()+minHeap.top())*1.0/2;
        }
    }
};

 

 

前 K 个高频元素

347. 前 K 个高频元素 - 力扣(LeetCode) (leetcode-cn.com)

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

  • 可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  • 你的算法的时间复杂度必须优于 $O(n \log n)$ , n 是数组的大小。
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

 用字典不就完事了吗?统计完还要排序的,排序用快排?

首先想到的就是map

map可以实现统计功能,但是对频数进行排序还是挺麻烦的,有没有可能我统计完,排序也出来了?有 ------容器适配器:优先级队列

可以理解为披着队列外衣的堆,常说的大小堆就是优先级队列

如果懒得自己实现的话,就直接用priority_queue(优先级队列)就可以了,底层实现都是一样的,从小到大排就是小顶堆,从大到小排就是大顶堆。

python中的大小堆 heapq - PiaYie - 博客园 (cnblogs.com)

大顶堆:每次弹出最大的元素

小顶堆:每次弹出最小的元素

思路:使用小顶堆存频数。当堆中数据多与k组时,每次把频数最小的数据弹出,最后返回的k个数据就是前 K 个高频元素

 

// 时间复杂度:O(nlogk)
// 空间复杂度:O(n)
class Solution {
public:
    // 小顶堆
    class mycomparison {
    public:
        bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
            return lhs.second > rhs.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 要统计元素出现频率
        unordered_map<int, int> map; // map<nums[i],对应出现的次数>
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }

        // 对频率排序
        // 定义一个小顶堆,大小为k
        priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;

        // 用固定大小为k的小顶堆,扫面所有频率的数值
        for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
            pri_que.push(*it);
            if (pri_que.size() > k) { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
                pri_que.pop();
            }
        }

        // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;

    }
};

 

posted @ 2021-10-14 17:01  PiaYie  阅读(357)  评论(0编辑  收藏  举报