Topk算法_topn算法

Topk算法_topn算法topK算法思路1:可以采用快速选择算法,借助快排,设mid为每次划分中间结果,每次划分完之后如果mid==k,则说明序列刚刚好,第k位置和他前面的位置都是前K大的数,如果mid < k,则说明第K大的元素在后半部分,则前半部分肯定是前K大的数,只需从后半部分找k – mid大的数即可,否则如果mid > k,则说明第K大的数在前半部分,只需从前半部分找前K大的数字即可。时间复杂度:假设每次划分的mid都在中间,每层都只是对一半做划分,所以每次划分的数据量为n,n/2,n/4,n/8…一

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

topK算法

思路1:快速选择算法
可以采用快速选择算法,借助快排,设mid为每次划分中间结果,每次划分完之后如果mid==k,则说明序列刚刚好,第k位置和他前面的位置都是前K大的数,如果mid < k,则说明第K大的元素在后半部分,则前半部分肯定是前K大的数,只需从后半部分找k – mid大的数即可,否则如果mid > k,则说明第K大的数在前半部分,只需从前半部分找前K大的数字即可。
时间复杂度:假设每次划分的mid都在中间,每层都只是对一半做划分,所以每次划分的数据量为
n,n/2,n/4,n/8…一共有logn层,根据等比数列可以算出来时间复杂度为O(n)
C++代码演示

#include<bits/stdc++.h>
#define x first
#define y second
#define send string::npos
#define lowbit(x) (x&(-x))
#define left(x) x<<1
#define right(x) x<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef struct Node * pnode;
const int N = 2e5 + 10;
const int M = 3 * N;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9;
int partion(int l,int r,int a[]){ 
   
    int x = a[l];
    while(l < r){ 
   
        while(l < r && a[r] < x)r --;
        if(l < r)a[l ++] = a[r];
        while(l < r && a[l] > x)l ++;
        if(l < r)a[r --] = a[l];
    }
    a[l] = x;
    return l;
}
int quickSort(int l,int r,int a[],int k){ 
   
    if(l < r){ 
   
        int mid = partion(l,r,a);		//划分结果
        int ls = mid - l + 1;   //[l,mid]一共有多少数
        if(ls == k)return;      //如果划分的mid恰好就是第K大的数
        if(ls < k)quickSort(mid + 1,r,a,k - ls);   //如果第K大的数在后半部分
        else quickSort(l,mid - 1,a,k);  //如果第K大的数在前半部分
    }
}
int main(){ 
   
    int a[] = { 
   3,2,3,1,2,4,5,5,6};
    int k = 4;
    quickSort(0,8,a,k);
    for(int i = 0;i < k;i ++)
        cout<<a[i]<<" ";
    return 0;
}

思路2:堆排序
可以建立一个大小为K的小顶堆,每次把当前数和小顶堆的堆顶作比较,如果当前数字大,则替换掉堆顶,重新调整堆。
时间复杂度:调整堆为O(logK),所以总的时间复杂度为nlog(K)

C++代码

#include<bits/stdc++.h>
#define x first
#define y second
#define send string::npos
#define lowbit(x) (x&(-x))
#define left(x) x<<1
#define right(x) x<<1|1
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef struct Node * pnode;
const int N = 2e5 + 10;
const int M = 3 * N;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9;
priority_queue<int,vector<int>,greater<int> >pq;  //默认是大顶堆
int main(){ 
   
    int k = 3;
    int a[] = { 
   3,1,5,2,4,3};
    for(int i = 0;i < 3;i ++)pq.push(a[i]);
    for(int i = 3;i < 6;i ++){ 
   
        if(pq.top() < a[i]){ 
   
            pq.pop();
            pq.push(a[i]);
        }
    }
    while(!pq.empty()){ 
   
        cout<<pq.top()<<endl;
        pq.pop();
    }
    return 0;
}

对比
堆方案只需要开辟K个数组空间即可,而且不需要变动原数组,而随机选择需要改原数组,如果不改动的话就需要创建一个O(n)的数组


leetcode例题
原题链接
数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

题解
1.快速选择版本

class Solution { 
   
public:
    int partion(int l,int r,vector<int>&nums){ 
   
        int x = nums[l];
        while(l < r){ 
   
            while(l < r && nums[r] < x)r --;
            if(l < r)nums[l ++] = nums[r];
            while(l < r && nums[l] > x)l ++;
            if(l < r)nums[r --] = nums[l];
        }
        nums[l] = x;
        return l;
    }
    void quickSort(int l,int r,vector<int>&nums,int k){ 
   
        if(l < r){ 
   
            int mid = partion(l,r,nums);
            int lnum = mid - l + 1;     //[l,mid]一共有多少个数
            if(k == lnum)return;
            if(k < lnum)quickSort(l,mid - 1,nums,k);
            else quickSort(mid + 1,r,nums,(k - lnum));
        }
    }
    int findKthLargest(vector<int>& nums, int k) { 
   
        quickSort(0,nums.size() - 1,nums,k);
        return nums[k - 1];
    }
};

2.优先队列版本

class Solution { 
   
public:
    int findKthLargest(vector<int>& nums, int k) { 
   
        priority_queue<int,vector<int>,greater<int> >pq;
        for(int i = 0;i < k;i ++)pq.push(nums[i]);
        for(int i = k;i < nums.size();i ++){ 
   
            if(pq.top() < nums[i]){ 
   
                pq.pop();
                pq.push(nums[i]);
            }
        }
        return pq.top();
    }
};
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168776.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • request对象和response对象

    request对象和response对象一、请求响应流程图 服务器处理请求的流程: (1)服务器每次收到请求时,都会为这个请求开辟一个新的线程。 (2)服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体! (3)服务器还会创建response对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应。   由流程图可以看出,在

    2022年6月12日
    45
  • 平面图上的欧拉公式

    平面图上的欧拉公式V-E+F=2,V、E、F表示顶点数、边数、面数。

    2022年5月26日
    37
  • 手机怎么模拟125k卡_手把手教你用手机NFC秒变门禁卡,这个方法多种手机都可以适用…

    手机怎么模拟125k卡_手把手教你用手机NFC秒变门禁卡,这个方法多种手机都可以适用…现在只要手机支持NFC功能,手机秒变公交卡、移动支付、数据传输、门禁卡等功能,之前在评论看多好多人说不知道怎么复制门禁卡,今天就来和大家讲解下如何复制门禁卡。我们以华为手机,前提是手机支持NFC功能的。第一步:门禁卡功能在钱包里面,所以首先找到华为钱包并打开,登录你的华为账号,在主页找到【门钥匙】。第二步:点击进入【门钥匙】后,点击【添加】,开始【模拟】门卡第三步:根据提示,将门卡放到手机背面NF…

    2022年5月24日
    417
  • 强化学习 模仿学习 于robot[通俗易懂]

    强化学习 模仿学习 于robot[通俗易懂]写在前面:分享知识是再好不过的事情。这篇文章主要是总结自己最近看的一些文章以及相关知识。自己在暑假实习的时候学习的就是在物理仿真平台上做robot的强化学习,未来读PhD的时候也被老师继续分配到了这个方向,哈哈。可能要一直从入门到入土了,趁着最近写researchproposal的时候,将最近的理解记录一下。鉴于笔者知识水平有限,若有不妥当之处,还请指出。摘要:robot强化学习模仿学…

    2022年9月19日
    1
  • eleUI Tab切换echarts显示问题

    eleUI Tab切换echarts显示问题eleUITab 切换 echarts 显示问题问题 使用 elementUI 中的 tab 切换选项卡 其中一个 tab 中内容是 echarts 图表 出现了图片空白期

    2025年8月27日
    0
  • volatile关键字作用

    volatile关键字作用一、作用简述内存可见性:保证变量的可见性:当一个被volatile关键字修饰的变量被一个线程修改的时候,其他线程可以立刻得到修改之后的结果。当一个线程向被volatile关键字修饰的变量写入数据的时候,虚拟机会强制它被值刷新到主内存中。当一个线程用到被volatile关键字修饰的值的时候,虚拟机会强制要求它从主内存中读取。 屏蔽JVM指令重排序(防止JVM编译源码生成class时使用重排序)…

    2022年6月1日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号