面试题 : Top-k问题

news2024/9/20 8:45:30

目录

题目

示例

提示

开始解题

1.思路

2.解题代码

3.时间复杂度

4.运行结果

​编辑

目前问题

真正的解法

1.以找前K个最大的元素为例

2.代码执行过程&&时间复杂度的计算

3.画图演示代码执行过程

4.解题代码

两种解法的比较

完结撒花✿✿ヽ(°▽°)ノ✿✿


博主推荐:毕竟面试题,还是动动你们的小手收藏一下,万一以后面试的时候遇到了,就赚到了!o(* ̄︶ ̄*)o

题目

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4
]

提示

  •   0 <= len(arr) <= 100000 
  •   0 <= k <= min(100000, len(arr))

开始解题

1.思路

  1. 建立小根堆,遍历这个数组把数组中的元素都放到小根堆中
  2. 定义一个数组ret作为返回值,,取k次堆顶元素放到数组中,返回ret

2.解题代码

public class Solution {
    /*
     * 这样写的话效率不是很高
     * */
    public int[] smallestK(int[] arr, int k) {
        int[] ret= new int[k];
        if(arr==null||k==0){
            return null;
        }
        //向上调整来建堆,时间复杂度为 O(N*logN)
        Queue<Integer> minHeap = new PriorityQueue<>();
        for (int i : arr) {
            minHeap.offer(i);
        }
        //poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null
        //每一次移除堆顶元素,都必须进行向下调整这棵二叉树,假设树的高度为h,时间复杂度log(h)
        //再加上循环k次,这段代码的时间复杂度为O(K * logH)
        for (int i = 0; i < k; i++) {
            ret[i]=minHeap.poll();
        }
        return ret;
    }
}

3.时间复杂度

        //向上调整来建堆,时间复杂度为 O(N*logN)
        Queue<Integer> minHeap = new PriorityQueue<>();
        for (int i : arr) {
            minHeap.offer(i);
        }
        //poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null
        //每一次移除堆顶元素,都必须进行向下调整这棵二叉树,假设树的高度为h,时间复杂度log(h)
        //再加上循环k次,这段代码的时间复杂度为O(K * logH)
        for (int i = 0; i < k; i++) {
            ret[i]=minHeap.poll();
        }

 所以上述解法的时间复杂度为:O(N*logN+K * logH)

4.运行结果

目前问题

代码运行效率不高,时间复杂度不行,太高了

       主要原因

        //向上调整来建堆,时间复杂度为 O(N*logN)
        Queue<Integer> minHeap = new PriorityQueue<>();
        for (int i : arr) {
            minHeap.offer(i);
        }

        //poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回null
        //每一次移除堆顶元素,都必须进行向下调整这棵二叉树,假设树的高度为H,由节点总数与树的高度关系可得:N=2^H-1=>H=log(N+1)
        //再加上循环k次,这段代码的时间复杂度为
O(K*logN)
        for (int i = 0; i < k; i++) {
            ret[i]=minHeap.poll();
        }


真正的解法

TOP-K问题:即求数据集合中前K个最大的元素或者最小的元素

TOP-K问题并不是将全部数据建立成堆,因为TOP-K问题一般情况下数据量都比较大。

真正的解法:是拿前K个建堆;找前K个最小的元素,建一个大根堆;找前K个最大的元素,建一个小根堆

TOP-K主要指的是在很大的一组数据的背景下进行,前K个元素仅仅只占很小的一部分,所以建堆和调整堆的时间复杂度也就变得很小了

1.以找前K个最大的元素为例

输入: arr = [27,15,19,18,28], k = 3

2.代码执行过程&&时间复杂度的计算

1.建立一个大小为K的小根堆(构造器默认的),没放元素,本质上是建立了一个大小为K的数组

2.遍历数组的前K个,放到小根堆minHeap当中 => 向上调整建堆
   时间复杂度: K*logK

3.遍历剩下的K-1个,每次和堆顶元素进行比较
   (1)如果该元素比堆顶元素小说明该元素一定不是前K个最大元素中的值,就不入堆;
   (2)如果该元素比堆顶元素大堆,则该元素与堆中最后个元素交换,再移除最后一个元素再把该元素入堆,
       入到最后一个先素的位置,调整该完全二叉树,使其再次成为个小根堆;
   时间复杂度:(N-K)*H=>(N-K)logK   注:(H为树的高度,K=2^H-1,H=log(K+1))
   (N-K)*H=>(N-K)*log(K+1)=>(N-K)logK

4.将堆中的元素放到ret里面,每次poll都是弹出堆中的最小值
   时间复杂度: K*logK

所以时间复杂度: K*logK+(N-K)*logK+ K*logK => N*logK + K*logK
   取近似值:O(N*logK)  注:K为常数,可忽略不计

3.画图演示代码执行过程

 注:

  • 小根堆中是前K个最大的值
  • 堆顶元素是这K个最大的值里面最小的
  • 最后的堆顶元素就是第K大的元素(牢记,面试官可能会问到!!!)
  • 当遍历到数组元素大于堆顶的时候,说明此时堆顶的元素一定不是前K个最大的值

4.解题代码

    /*
    * 前k个最大的元素
    * 时间复杂度:K*logK
    * */
    public static int[] largestK(int[] arr, int k) {
        int[] ret = new int[k];
        if (arr==null||k==0){
            return null;
        }
        //1.建立一个大小为K的小根堆(构造器默认的),没放元素,本质上是建立了一个大小为K的数组

        Queue<Integer> minHeap = new PriorityQueue<>(k);
        //2.遍历数组的前K个,放到小根堆minHeap当中
        //时间复杂度: K*logK+(N-K)logK+ K*logK
        //取近似值:O(N*logK)
        for (int i = 0; i < k; i++) {
            minHeap.offer(arr[i]);
        }
      /* 3.遍历剩下的K-1个,每次和堆顶元素进行比较
        (1)如果该元素比堆顶元素小说明该元素一定不是前K个最大元素中的值,就不入堆;
        (2)如果该元素比堆顶元素大堆,则该元素与堆中最后个元素交换,再移除最后一个元素再把该元素入堆,
        入到最后一个先素的位置,调整该完全二叉树,使其再次成为个小根堆*/
        //时间复杂度:(N-K)*H=>(N-K)logK
        //注:(H为树的高度)K=2^H-1,H=log(K+1)
        //(N-K)*H=>(N-K)*log(K+1)=>(N-K)logK
        for (int i = k; i <arr.length ; i++) {
            int heapTop = minHeap.peek();
            if (arr[i]>heapTop){
                minHeap.poll();
                minHeap.offer(arr[i]);
            }
        }
        //4.将堆中的元素放到ret里面,每次poll都是弹出堆中的最小值
        //时间复杂度: K*logK
        for (int i = 0; i < k; i++) {
            ret[i]=minHeap.poll();
        }
        return ret;
    }

两种解法的比较

第一种解法时间复杂度为:O(N*logN+K * logN)

第二种解法时间复杂度为:O(N*logK)

注:K是常数,且数值与N相比极小

第二种解法远远优于第一种解法,面试官看到会给你竖起大拇指的

完结撒花✿✿ヽ(°▽°)ノ✿✿

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/902955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CAPL通过lookupSignal和DBLookup获取DBC信号的属性信息

文章目录 演示CAPL通过lookupSignal和DBLookup获取DBC信号的属性信息lookupSignalDBLookup代码问题:DBLookup(信号名).AttributeName报错问题: motorola格式的信号使用DBLookup获取信号的bitstart跟ig模块里的信息不一样演示 CAPL通过lookupSignal和DBLookup获取DBC信号的属性…

Django的模型

定义模型 from django.db import models class User(models.Model):# 类属性是表示表的字段username models.CharField(max_length50,uniqueTrue)password models.CharField(max_length200)create_time models.DateTimeField(auto_now_addTrue) # auto_now_add新增数据时间…

发布python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api,以及安卓接入案例代码

python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api&#xff0c;以及原生安卓接入案例代码案例 源码地址:keyxh/newsapi: python模仿2023年全国职业的移动应用开发赛项样式开发的开源的新闻api&#xff0c;以及安卓接入案例代码 (github.com) 目录 1.环境配…

全球地震分析寻找难以捉摸的前震信号

发现前震的本质可以帮助地震学家预测大地震。 2019 年里奇克莱斯特地震序列使南加州沙漠​​的道路发生偏移。图片来源&#xff1a;Ken Hudnut/USGS 小地震是否预示着大地震是地震学中长期存在的问题。 简而言之&#xff0c;答案是&#xff0c;有时他们会这样做。这是根据对全…

老胡的周刊(第104期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 whistle[2] Whistle 是基于 Node 实现的跨平…

点亮一颗LED灯

TOC LED0 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能APB2的外设时钟GPIO_InitTypeDef GPIO_Initstructure;GPIO_Initstructure.GPIO_Mode GPIO_Mode_Out_PP;//通用推挽输出GPIO_Initstructure.GPIO_Pin GPIO_Pin_5;GPIO_Initstructure.GPIO_Speed GPIO_S…

从LeakCanary看如何判断对象被回收了

前面已经了解了Service&#xff0c;Fragment&#xff0c;ViewModel对象的销毁时机&#xff0c;那么在触发销毁时机后&#xff0c;我们怎么判断这些对象有没有回收呢&#xff1f; 大家都知道在Java中有强引用&#xff0c;弱引用&#xff0c;软引用&#xff0c;虚引用四种引用方…

难缠客户背后的秘密:项目经理的危机处理手册

难缠的客户&#xff0c;每个项目经理都会或多或少遇到。他们可能会频繁更改需求&#xff0c;对细节吹毛求疵&#xff0c;或者在关键时刻提出与之前完全不同的意见。但是&#xff0c;难缠的客户其实并不都是坏事&#xff0c;他们也为项目经理提供了宝贵的学习机会。本文将深入探…

git拉取失败/git fatal终极解决方法

前言 被折磨不下20次总结出来的终极方案 步骤 0 首先关闭代理试试&#xff0c;不行就下一步 1 重置代理或者取消代理的方式 git config --global --unset http.proxy git config --global --unset https.proxy添加全局代理 git config --global http.proxy git config …

虚拟化 VMware sphere

一 VMware sphere用途&#xff1a; VMware vSphere 是 VMware 的虚拟化平台&#xff0c;可将数据中心转换为包括 CPU、存储和网络资源的聚合计算基础架构。vSphere 将这些基础架构作为一个统一的运行环境进行管理. 1. **虚拟化&#xff1a;** vSphere 的主要用途是将物理服务…

打印X型的图案

int main() {int n0;int i0;int j0;scanf("%d",&n);for(i0;i<n;i){for(j0;j<n;j){if(ij){printf("*");}else if((ij)n-1){printf("*");}elseprintf(" ");}printf("\n");}return 0; }

mapper.xml中循环执行多条语句时报错,但是单独拿SQL到数据库却可以执行

我是批量修改数据&#xff0c;用foreach标签包住update语句&#xff0c;报错信息如下&#xff1a; nested exception is java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the …

HCIP的VLAN实验

实验步骤&#xff1a; 1.首先&#xff0c;对交换机SW1进行操作&#xff0c;创建需要的VLAN并对接口进行划分 [SW1]vlan batch 2 to 6 [SW1]port-group group-member Ethernet 0/0/2 Ethernet 0/0/4 [SW1-port-group]port link-type access [SW1-port-group]port default vlan …

聚焦电力行业CentOS迁移,麒麟信安受邀参加第六届电力信息通信新技术大会暨数字化发展论坛并发表主题演讲

为加快推进“双碳”目标下的新型能源体系和新型电力系统建设&#xff0c;深化新一代数字技术与电力业务的融合发展&#xff0c;促进电力行业关键技术自主创新、安全可控&#xff0c;助力电力企业数字化转型升级和高质量发展&#xff0c;2023年8月9-11日&#xff0c;第六届电力信…

使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。

一.根据自己版本选择镜像 uname -a cat /etc/centos-releaseuname -a 命令用于查看当前系统的硬件和操作系统信息&#xff0c;包括内核版本、处理器架构、系统类型等。 其中&#xff0c;"Linux" 表示操作系统类型为 Linux&#xff0c;"3.10.0-1160.el7.x86_64…

C++ 网络编程项目fastDFS分布式文件系统(四)-fastCGI项目相关技术以及linux搜狗输入法相关问题。

目录 1. Nginx作为web服务器处理请求 2. http协议复习 Get方式提交数据 Post方式提交数据 3. fastCGI 3.1 CGI 3.2 fastCGI 3.3 fastCGI和spawn-fcgi安装 1. 安装fastCGI 2. 安装spawn-fcgi 3.4 nginx && fastcgi 4其他知识点 1. fastCGI环境变量 - fas…

week5刷题

题解: 斐波那契数的边界条件是 F(0)0和 F(1)1。当 n>1 时&#xff0c;每一项的和都等于前两项的和&#xff0c;因此有如下递推关系&#xff1a; F(n)F(n−1)F(n−2) 由于斐波那契数存在递推关系&#xff0c;因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推…

vector的迭代器失效问题

vector的迭代器存在一定隐患&#xff0c;以下几种方式会导致其迭代器失效 resize、reserve、insert、assign、push_back。 1.push_back导致迭代器失效 示例代码&#xff1a; #include<vector> #include <iostream> using std::cout; using std::endl; using std:…

PyTorch学习笔记(十六)——利用GPU训练

一、方式一 网络模型、损失函数、数据&#xff08;包括输入、标注&#xff09; 找到以上三种变量&#xff0c;调用它们的.cuda()&#xff0c;再返回即可 if torch.cuda.is_available():mynn mynn.cuda() if torch.cuda.is_available():loss_function loss_function.cuda(…

无涯教程-PHP - 预定义变量

PHP为它运行的脚本提供了预定义变量数组&#xff0c;其中包含来自Web服务器&#xff0c;环境和用户输入的变量。这些新数组称为超全局变量- PHP超全局变量 Sr.NoVariable & Description1 $GLOBALS 全局变量数组。 2 $_SERVER 存放提交过来的web路径、域名、来源、IP及各…