Leetcode——703. 数据流中的第K大元素

在这里插入图片描述
用小根堆的思路:
首先建立一个由最大k个元素形成的小根堆,add元素时进行比较,如果元素小雨堆顶元素,则直接返回堆顶元素,如果大于等于堆顶元素,就删除堆顶节点,并将add的元素插入堆。插入删除时间复杂度均为O(logn)。
建堆的过程比较复杂,首先要考虑初始的nums数组大小与k的关系,如果大于k则直接建堆,后续只需要比较就好了,如果小于k(k-1),则要第一次add的时候先建堆。
删除堆顶元素:将堆顶元素值令为堆尾元素值(因为堆用数组表示(数组下标开始为1),所以堆尾就是下标为k,堆顶就是下标为1),然后从上往下规约。规约也很简单,与左右儿子(与父节点下标n的关系为2n和2n+1)比大小,如果大于儿子,则交换,直至换至堆底。
添加元素:将add的元素直接令为堆尾巴,然后从下向上规约,即于父节点比较(子节点j,父节点则为j/2),如果子节点小于父节点则交换,直至换至堆顶。
在这里插入图片描述

附代码

#include <iostream>
#include <vector>
using namespace std;

class KthLargest
{
public:
    int num;
    int countnum=0;
    vector<int> minHeap;
    KthLargest(int k, vector<int>& nums)
    {
        num=k;
        minHeap.resize(k+1);
        minHeap[0]=-1;
        int guodu;
        int j;  //j用来插入节点时维护堆
        //如果初始化的数组大小小于要求的k项
        if(nums.size()<=k)
        {
            for(int i=0;i<nums.size();i++)
            {
                j=i+1;
                minHeap[j]=nums[i];
                while (j/2 > 0 && minHeap[j] < minHeap[j/2])
                {
                    // 自下往上堆化
                    guodu=minHeap[j/2];
                    minHeap[j/2]=minHeap[j];
                    minHeap[j]=guodu;
                    j = j/2;
                }
                countnum++;
            }
        }
        //如果初始化的数组大小大于要求的k项
        else
        {
            countnum=k;
            //先建立一个k个元素的小根堆(用最大的k个元素)
            for(int i=0;i<k;i++)
            {
                j=i+1;
                minHeap[j]=nums[i];
                while (j/2 > 0 && minHeap[j] < minHeap[j/2])
                {
                    // 自下往上堆化
                    guodu=minHeap[j/2];
                    minHeap[j/2]=minHeap[j];
                    minHeap[j]=guodu;
                    j = j/2;
                }

            }
            for(int i=0;i<nums.size()-k;i++)
            {
                if(nums[i+k]>=minHeap[1])
                {
                    //删除顶点
                    minHeap[1]=minHeap[num];
                    int upToDown=1;
                    int minPos = upToDown;
                    while (true)
                    {
                        minPos = upToDown;
                        if (upToDown*2 <= num && minHeap[upToDown] > minHeap[upToDown*2])
                            minPos = upToDown*2;
                        if (upToDown*2+1 <= num && minHeap[minPos] > minHeap[upToDown*2+1])
                            minPos = upToDown*2+1;
                        if (minPos == upToDown)
                            break;
                        // swap(a, i, minPos);
                        guodu=minHeap[upToDown];
                        minHeap[upToDown]=minHeap[minPos];
                        minHeap[minPos]=guodu;
                        upToDown = minPos;
                    }
                    //插入新节点
                    minHeap[num]=nums[i+k];
                    j=num;
                    while (j/2 > 0 && minHeap[j] < minHeap[j/2])
                    {
                        // 自下往上堆化
                        guodu=minHeap[j/2];
                        minHeap[j/2]=minHeap[j];
                        minHeap[j]=guodu;
                        j = j/2;
                    }
                }
            }
        }
    }

    int add(int val)
    {
        int guodu;
        if(countnum<num)
        {
            countnum++;
            int index=countnum;
            minHeap[index]=val;
            int j=index;
            while (j/2 > 0 && minHeap[j] < minHeap[j/2])
            {
                // 自下往上堆化
                guodu=minHeap[j/2];
                minHeap[j/2]=minHeap[j];
                minHeap[j]=guodu;
                j = j/2;
            }
            return minHeap[1];
        }
        else
        {
            if(val<minHeap[1])
            {
                return minHeap[1];
            }
            else
            {
                //删除顶点
                minHeap[1]=minHeap[num];
                int i=1;
                int minPos = i;
                while (true)
                {
                    minPos = i;
                    if (i*2 <= num && minHeap[i] > minHeap[i*2])
                        minPos = i*2;
                    if (i*2+1 <= num && minHeap[minPos] > minHeap[i*2+1])
                        minPos = i*2+1;
                    if (minPos == i)
                        break;
                    guodu=minHeap[i];
                    minHeap[i]=minHeap[minPos];
                    minHeap[minPos]=guodu;
                    i = minPos;
                }
                //插入新节点
                minHeap[num]=val;
                int j=num;
                while (j/2 > 0 && minHeap[j] < minHeap[j/2])
                {
                    // 自下往上堆化
                    guodu=minHeap[j/2];
                    minHeap[j/2]=minHeap[j];
                    minHeap[j]=guodu;
                    j = j/2;
                }
                return minHeap[1];
            }
        }
    }
};

int main()
{
    int k=3;
    int val=3;
    vector<int> nums;
    nums.push_back(4);
    nums.push_back(5);
    KthLargest* obj = new KthLargest(k, nums);
    cout<<obj->add(3)<<endl;
    cout<<obj->add(5)<<endl;
    cout<<obj->add(10)<<endl;
    cout<<obj->add(9)<<endl;
    cout<<obj->add(3)<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值