饭后小甜点leetcode——堆

饭后小甜点leetcode——堆

堆的基础实现

MaxHeap.cs

MinHeap.cs

IndexMinHeap.cs

703. Kth Largest Element in a Stream

Design a class to find the kth largest element in a stream. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Your KthLargest class will have a constructor which accepts an integer k and an integer array nums, which contains initial elements from the stream. For each call to the method KthLargest.add, return the element representing the kth largest element in the stream.

Example:

int k = 3;
int[] arr = [4,5,8,2];
KthLargest kthLargest = new KthLargest(3, arr);
kthLargest.add(3); // returns 4
kthLargest.add(5); // returns 5
kthLargest.add(10); // returns 5
kthLargest.add(9); // returns 8
kthLargest.add(4); // returns 8

思路:
用优先队列,但要定义为小顶堆那种弹出规则。先入队,如果优先队列中总元素个数超过了k,那么就弹出,使得top始终为第k大的值。

代码(C++):

class KthLargest {
public:
    priority_queue<int, vector<int>, greater<int>> pq;
    // 使用优先队列需要 #include<queue>
class KthLargest {
public:    
    priority_queue<int, vector<int>, greater<int>> pq;
    // 使用优先队列需要 #include<queue>
    // 默认情况下不需要写后两个参数,默认为大顶堆,优先弹出最大的,此时我们需要优先弹出最小的,于是加上后两个参数,虽然第三个参数看上去像是弹出较大的。。。但并不是这样的,注意下下
    // 当自己在IDE里写的时候,可能 greater会报错,说 greater不是模板,这时候只要 #include<functional>即可
    int size;// 记录k值

    // 构造函数
    KthLargest(int k, vector<int> nums) {
        size = k;
        for (int i = 0;i < nums.size();i++) {
            pq.push(nums[i]);
            if (pq.size() > k) {
                pq.pop();
            }
        }
    }

    int add(int val) {
        pq.push(val);
        if (pq.size() > size) {
            pq.pop();
        }
        return pq.top();
    }
};
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest obj = new KthLargest(k, nums);
* int param_1 = obj.add(val);
*/

295. Find Median from Data Stream

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

For example,
[2,3,4], the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Design a data structure that supports the following two operations:

void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.

Example:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2

思路
该题要求寻找数据流中的中位数,首先得明白什么是中位数,中位数即一组排好序的数中最中间那一个儿数,如果该组数是偶数个数,中位数就是最中间两个的平均值。这样一来我们可以把这组数分成两堆,一个大顶堆放较小的那一拨儿数字,一个小顶堆放较大的那一拨儿数字,这样的话从堆顶就可以得到中位数。那么难点就在于如何调整这两个堆,使得它们两刚好一个放较小的那拨儿数,一个放较大的那拨儿数。可以这样想,首先把新来的数放到较小数堆里一下,如果它成了大顶堆的顶点,说明它很可能应该放到较大数堆里,于是弹出堆顶;如果它没成大顶堆顶点,那说明它来对地方了,但是小数堆的个数变多了,为了平衡,得弹出一个最大的给大数堆,所以无论如何都得把小数堆堆顶弹出给大数堆。完了以后如果大数堆个数比小数堆多了,得把它最小的那个给小数堆。

代码(C++)

class MedianFinder {
    priority_queue<int> lo;                              // max heap
    priority_queue<int, vector<int>, greater<int>> hi;   // min heap

public:
    // Adds a number into the data structure.
    void addNum(int num)
    {
        lo.push(num);                                    // Add to max heap

        hi.push(lo.top());                               // balancing step
        lo.pop();

        if (lo.size() < hi.size()) {                     // maintain size property
            lo.push(hi.top());
            hi.pop();
        }
    }

    // Returns the median of current data stream
    double findMedian()
    {
        return lo.size() > hi.size() ? (double) lo.top() : (lo.top() + hi.top()) * 0.5;
    }
};

239. Sliding Window Maximum

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

Example:

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3
Output: [3,3,5,5,6,7]
Explanation:

Window position Max


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
Note:
You may assume k is always valid, 1 ≤ k ≤ input array’s size for non-empty array.

思路1:
这题可以用堆试试,但做出来效率有点低,就是每移动一下窗口新建一个堆然后返回堆顶(基本把堆当成了自动排序工具。。)先上一下代码。
代码1(C++):

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        if (nums.empty()) {
            return res;
        }
        for (int i = 0;i <= nums.size()-k;i++) {
            priority_queue<int> pq;
            for (int j = i;j < i+k;j++) {
                pq.push(nums[j]);
            }
            res.push_back(pq.top());
        }
        return res;
    }
};

思路2:
这个题其实最好用双头队列,在deque中保存窗口在数组中对应的首尾下标,然后对于新来的数,从右到左看,只要比新来的小就pop,最后dq中剩下的数中最左边的应该是最大的,为啥不能从左往右删呢,因为如果这样的话,新来的数大小如果刚好处于中间的位置就不好判断了。

代码2(C++):

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        if (nums.empty()) {
            return res;
        }
        deque<int> dq;
        for (int i = 0;i < nums.size();i++) {
            if (!dq.empty() && dq.front() == i-k) {
                dq.pop_front();
            }
            while (!dq.empty() && nums[i] > nums[dq.back()]) {
                dq.pop_back();
            }
            dq.push_back(i);
            if (i >= k - 1) {
                res.push_back(nums[dq.front()]);
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值