首页 > 其他分享 >Top K问题

Top K问题

时间:2024-04-14 17:25:24浏览次数:13  
标签:index cur nums int Top 元素 问题 void

问题

求解乱序数组中第k个数

利用堆实现

时间复杂度是\(O(nlogk)\)。以求第K大的数为例,建立小根堆,即堆顶元素为当前遍历的数字中最小值,当堆的长度大于k时,弹出堆顶元素,最后返回堆顶元素即可
在C++中直接使用优先队列 priority_queue即可

手写堆

为了实现类似的功能,手写堆需要提供3个接口,分别是pop()、top()、push()
当pop()堆顶元素过后,需要将最后一个元素,放在堆顶,然后重新调整堆的结构
当push()一个元素后,先在堆最后开辟一个空间,然后为这个元素寻找合适位置,调整堆的结构

#include <iostream>
#include <vector>
using namespace std;
const int N = 1e9+5;
vector<int> h(N);
//堆的大小
int m = 0;
//小根堆 index为下标位置

//up操作 实现push后的位置调整
//对于下标index其父节点下标就是index/2
void up(int index)
{
    while(index/2 > 0 && h[index] < h[index/2])
    {
        swap(h[index/2],h[index]);
        index /= 2;
    }
}

//down操作 实现pop后调整位置
//寻找index下标位置的合适位置,即向下寻找
void down(int index)
{
    while(index <= m)
    {
        int cur = index;
        if(index*2 <= m && h[cur] > h[index*2]) cur = index*2;
        if(index*2+1 <= m && h[cur] > h[index*2 + 1]) cur = index*2 + 1;
        if(index == cur) break;
        swap(h[cur],h[index]);
        index = cur;
    }
}

//实现push接口
void push(int val)
{
    h[++m] = val;
    //调整val的位置
    up(m);
}

//实现top接口
int top()
{
    return m >= 1 ? h[1] : -1;
}

//实现pop接口
void pop()
{
    //将最后的元素替代顶部元素
    h[1] = h[m--];
    //调整位置
    down(1);

}

堆排序

堆排序其实和上述方法类似,其时间复杂度为\(O(nlogn)\),不稳定
通过将数组构成一个大顶堆,然后交换堆顶和最后一个数,那么此时最大值就排好了位置,然后再对0~n-1个数进行重复操作。

  1. 将数组构建为大顶堆
  2. 交换堆顶元素和数组末尾元素
  3. 将剩余的0~n-1个数重新构成大顶堆,然后重复直到有序
//构建大顶堆
//原始数组,待调整下标pa,数组大小
void makeheap(vector<int>& nums,int pa, int n)
{
    int temp = nums[pa];
    //循环变量
    int parent,child;
    for(parent = pa;(parent*2+1)<n;parent = child)
    {
        //寻找最大的子节点
        child = 2*parent+1;
        if(child != n-1 && nums[child] < nums[child+1])
        {
            child++;
        }
        if(temp >= nums[child])
        {
            break;
        }
        else{
            nums[parent] = nums[child];
        }
    }
    nums[parent] = temp;
}

//堆排序
void heapsort(vector<int>& nums,int n)
{
    //建立最大堆
    for(int i = n/2-1;i>=0 ;i--)
    {
        makeheap(nums,i,n);
    }
    //移动大值到最后,重新构建大顶堆
    for(int i = n-1;i>=0;i--)
    {
        swap(nums[i],nums[0]);
        makeheap(nums,0,i);
    }
}

快速排序实现

时间复杂度为O(n),就是通过基准将数组分为两部分,然后当小于基准的部分长度大于k,那么就在小于的部分递归寻找,大于k就在大于基准的部分递归寻找

int quick_sort(vector<int>& nums,int l,int h,int k)
{
    if(l==h) return nums[l];
    int i = l-1;
    int j = h+1;
    int mid = nums[l+h >> 1];
    while(i<j)
    {
        while(nums[++i] < mid);
        while(nums[--j] > mid);
        if(i<j) swap(nums[i],nums[j]);
    }
    //l...j j+1...h
    int len = j-l+1;
    if(len >= k) return quick_sort(nums,l,j,k);
    else return quick_sort(nums,j+1,h,k-len);
}

总结

可以看到
对于堆排序,可以去寻找第K大的数
对于快速选择,可以去寻找第K小的数
当然如果长度为n,第K大的数也是第n-k+1小的数

标签:index,cur,nums,int,Top,元素,问题,void
From: https://www.cnblogs.com/XTG111/p/18134377

相关文章

  • 用户登录功能遇到的问题总结
    Cookie和Sessionsessionid每个用户都有自己的session,不同用户之间session是隔离的,这个由所有的session插件或者tomcat服务器自己维护分布式环境下用户信息保存到服务器的Session下就不靠谱了,不同节点的服务器sessioin数据并不会主动同步。使用服务器自身的session注意问题......
  • P8741 [蓝桥杯 2021 省 B] 填空问题 题解
    题目传送门试题A:空间【解析】本题考察计算机存储的基础知识,只要掌握空间存储的换算方法,就能够算出答案。【程序】#include<bits/stdc++.h>usingnamespacestd;intmain(){printf("%d\n",256*8/32*1024*1024);return0;}【答案】67108864......
  • P8679 [蓝桥杯 2019 省 B] 填空问题 题解
    题目传送门试题A:组队【解析】本题是一道经典的DFS搜索题,每次对各号位的选手进行DFS,找到各号位上有成绩的选手时再进行进一步搜索即可。【程序】#include<bits/stdc++.h>usingnamespacestd;intteam[20][6];intmax_sum;boolvis[20];voiddfs(intu,intsu......
  • P8741 [蓝桥杯 2021 省 B] 填空问题 题解
    题目传送门试题A:空间【解析】本题考察计算机存储的基础知识,只要掌握空间存储的换算方法,就能够算出答案。【程序】#include<bits/stdc++.h>usingnamespacestd;intmain(){printf("%d\n",256*8/32*1024*1024);return0;}【答案】67108864......
  • js中this指向问题
    this是什么?在不同的场景,this指代的含义不同:在全局代码中使用this,指代全局对象(window)在真实的开发中,很少在全局代码使用this在函数中使用this,它的指向完全取决于函数是如何被调用的调用方式示例函数中的this指向通过new调用newmethod()新对象直接调......
  • ES7.17.20连接时报错:java.lang.NoSuchMethodError: org.elasticsearch.client.Request
    1.报错详情:java.lang.NoSuchMethodError:org.elasticsearch.client.RequestOptions$Builder.removeHeader(Ljava/lang/String;)Lorg/elasticsearch/client/RequestOptions$Builder; atco.elastic.clients.transport.rest_client.RestClientOptions.addBuiltinHeaders(RestCli......
  • 本地升级idea后,不能向github上提交代码问题处理
    问题现象:本人自己电脑之前一直使用idea2018.1商业破解版,之前有简历本地代码仓库,并在github上建立了关联的远程代码仓库。最近本人在本地升级一下idea,从idea2018.1商业版升级到2023.1.5社区版本(idea支持win7的版本基本就到2023.1这个版本了,目前本人尝试安装了2023.1.5和2023.1.3......
  • 【Nano Framework ESP32 篇】刷入 nanoCLR 固件以及相关问题
    老周在几个世纪前曾写过树莓派相关的iOT水文,之所以没写NanoFramework相关的内容,是因为那时候这货还不成熟,可玩性不高。不过,这货现在已经相对完善,老周都把它用在项目上了——第一个是自制的智能插座,这个某宝上50多块可以买到,搜“esp32插座”就能找到。一种是86型盒子的,带屏......
  • Android 11 导航栏添加一个虚拟按钮--问题合集
    导航栏添加一个虚拟按钮按钮功能:显示隐藏导航栏1.frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.javaprotectedStringgetDefaultLayout(){finalintdefaultResource=QuickStepContract.isGesturalMode(mN......
  • [Java SE] 经典问题:超出Java Long型(8字节/64位)的二进制比特流数据如何进行大数的数
    0问题描述经典问题:超出JavaLong型(8字节/64位)的二进制比特流数据如何进行大数的数值计算?近期工作上遇到了这个问题:需要将一个无符号数、且位长>=8字节(等于8字节时,首位bit为1,其他bit不全为0)的二进制字符串转为Java****对象(原始整数),进行整型运算、或浮点数运算浮点运算......