线性时间选择(Top K)问题(Java)

news2025/8/12 3:56:32

线性时间选择(Top K)问题(Java)

文章目录

  • 线性时间选择(Top K)问题(Java)
    • 1、前置介绍
    • 2、分治法求解
    • 3、代码实现
    • 4、复杂度分析
    • 5、扩展
    • 6、参考资料


在这里插入图片描述


1、前置介绍

定义

选择问题(select problem)是指在n个元素的集合中,选出某个元素值大小在集合中处于第k位的元素,
即所谓的求第k小元素问题(kth-smallest)。

元素选择问题的一般提法

给定具有n个元素的一个线性序集和一个整数k,其中,l<=k<=n,题目要求找出这n个元素中第k小的元素, 即如果将这n 个元素依其线性序排列时,排在第k个的元素即为要找的元素。

易知,

  • k=l时,就是要找最小元素;
  • k=n时,就是要找最大元素;
  • k= (n+l)/2时,称为找中位数。

在某些特殊情况下,很容易设计出解选择问题的线性时间算法。

例如,找n个元素的最小元素和最大元素显然可以在O(n)时间完成。如果k<=n/logn, 通过堆排序算法可以在
O(n+klogn) = O(n)时间内找出第k小元素。 当k>=n-n/logn时也一样。

2、分治法求解

一般的选择问题, 特别是中位数的选择问题似乎比找最小元素要难。但事实上, 从渐近阶的意义上看,它们是一样的。
一般的选择问题也可以在OCn) 时间内得到解决。

设原表长度为n,假定经过一趟划分,分成左右两个子表,其中左子表是主元及其左边元素的子表,设其长度为j,右子表是主元右边元素的子表。那么,若k=j,则主元就是第k小元素;否则若k<j,第k小元素必定在左子表中,需求解的子问题成为在左子表中求第k小元素;若k>j,则第k小元素必定在右子表中,需求解的子问题成为在右子表中求第k-j小元素。

下面要讨论解一般的选择问题的分治算法randomizedSelect。该算法实际上是模仿快速排序算法设计出来的。
其基本思想也是对输入数组进行递归划分。与快速排序算法不同的是,它只对划分出的子数组之一进行递归处理。

随机选主元算法

假定表中元素各不相同,并且随机选择主元,即在下标区间[left,right]中随机选择一个下标r,以该下标处的元素为主元。

要找数组arr[0:n-1]中第K小元素只要调用randomizedSelect(arr, 0, n -1, k)即可。

具体算法可描述如下:

private static Comparable randomizedSelect(int p,int r,int k) {
    if (p==r) return a[p];
    int i=randomizedpartition(p,r),
    j = i - p + 1;
    if (k<=j) {
        return randomizedSelect(p,i,k);
    } else {
        return randomizedSelect(i+1,r,k-j);
    }
}

3、代码实现

  • 将n个输入元素划分成 ⌈ n / 5 ⌉ \lceil n/5 \rceil n/5个组,每组5个元素,只可能有一个组不是5个元素。用任意一种排序算法,将每组中的元素排好序,并取出每组的中位数,共 ⌈ n / 5 ⌉ \lceil n/5 \rceil n/5个。

  • 递归调用select来找出这 ⌈ n / 5 ⌉ \lceil n/5 \rceil n/5个元素的中位数。如果 ⌈ n / 5 ⌉ \lceil n/5 \rceil n/5是偶数,就找它的2个中位数中较大的一个。以这个元素作为划分基准。

在这里插入图片描述

例子

在这里插入图片描述

解题步骤

(1)把前面25个元素分为5(= ⌊ 29 / 5 ⌋ \lfloor 29/5 \rfloor 29/5)组:
(8,31,60,33,17),(4,51,57,49,35),(11,43,37,3,13),(52,6,19,25,32),(54,16,5,41,7)

(2)提取每一组的中值元素,构成集合{31,49,13,25,16};

(3)递归地使用算法求取该集合的中值,得到m=25:

(4)根据m=25,把29个元素划分为3个子数组:

  • P = {8,17,4,11,3,13,6,19,16,5,7,23,22}
  • Q = {25}
  • R = {31,60,33,51,57,49,35,43,37,52,32,54,41,46,29}

(5)由于P=13、Q=1、k=18,所以放弃P、Q,使k=18-13-1=4,对R递归地执行本算法:

(6)将R划分成3( ⌊ 18 / 5 ⌋ \lfloor 18/5 \rfloor 18/5)组:
{31,60,33,51,57},{49,35,43,37,52},{32,54,41,46,29}

(7)求取这3组元素的中值元素分别为:{51,43,41},这个集合的中值元素是43;

(8)根据43将R划分成3组:
{31,33,35,37,32,41,29},{43},{60,51,57,49,52,54,46}

(9)因为k=4,第一个子数组的元素个数大于k,
所以放弃后面两个子数组,以k=4对第一个子
数组递归调用本算法;

(10)将这个子数组分成5个元素的一组:
{31,33,35,37,32},取其中值元素为33:

(11)根据33,把第一个子数组划分成{31,32,29},{33},{35,37,41}

(12)因为k=4,而第一、第二个子数组的元素个数为4,所以33即为所求取的第18个小元素。

private static Comparable select (int p, int r, int k) {
      if (r - p < 5) {  // 如果元素个数小于5,可以直接返回结果
        // 用某个简单排序算法对数组a[p:r]排序;
        bubbleSort(p, r);
        return a[p + k - 1];
      }
      // 将a[p + 5 * i]至a[p + 5 * i + 4]的第3小元素
      // 与a[p+i]交换位置;
      // 找中位数的中位数,r-p-4即上面所说的n-5
      for (int i = 0; i<= (r - p - 4) / 5; i++) {
         int s = p + 5 * i, t = s + 4;
         for (int j = 0; j < 3; j++) {
           bubble(s, t - j);
         }
         MyMath.swap(a, p+i, s+2);
      }
      Comparable x = select(p, p + (r - p - 4) / 5, (r - p + 6)/ 10);
      int i = partition(p,r,x), j = i - p + 1;
      if (k <= j) {
        return select(p,i,k);
      } else {
        return select(i+1,r,k-j);
      }
}

4、复杂度分析

在最坏情况下,算法randomizedSelect需要O(n2)计算时间(在找最小元素时,总是在最大元素处划分)

但可以证明,算法randomizedSelect可以在O(n)平均时间内找出n个输入元素中的第k小元素。

如果能在线性时间内找到一个划分基准,使得按这个基准所划分出的2个子数组的长度都至少为原数组长度的ε倍(0<ε<1是某个正常数),那么就可以在最坏情况下用O(n)时间完成选择任务。

例如,若ε=9/10,算法递归调用所产生的子数组的长度至少缩短1/10。所以,在最坏情况下,算法所需的计算时间T(n)满足递归式T(n)≤T(9n/10)+O(n) 。

由此可得T(n)=O(n)。

在这里插入图片描述

设所有元素互不相同。在这种情况下,找出的基准x至少比3(n-5)/10个元素大,因为在每一组中有2个元素小于本组的中位数,而n/5个中位数中又有(n-5)/10个小于基准x。同理,基准x也至少比3(n-5)/10个元素小。而当n≥75时,3(n-5)/10≥n/4所以按此基准划分所得的2个子数组的长度都至少缩短1/4。(备注:就是说明递归子问题规模是下降的,划分后的两个子数组分别至多有3n/4个元素)

在这里插入图片描述

上述算法将每一组的大小定为5,并选取75作为是否作递归调用的分界点。这2点保证了T(n)的递归式中2个自变量之和n/5+3n/4=19n/20
=εn,0<ε<1。这是使T(n)=O(n)的关键之处。当然,除了5和75之外,还有其他选择。

递归树

在这里插入图片描述

5、扩展

分组为什么5个元素一组?3个一组或7个一组行不行?

分析:递归调用

1、求x的工作量与中位数集合的规模有关,其值=n/t有关,t为每组元素数,t越大,其规模越小

2、规约后子问题大小与分组元素数t有关,t越大,子问题规模大。

在这里插入图片描述
在这里插入图片描述

6、参考资料

  • 算法分析与设计(第四版)

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

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

相关文章

docker可视化与制作和提交自己的镜像

第四章docker可视化 portainer docker的图形化管理工具&#xff01;提供一个后台面板供我们操作&#xff01; docker run -d -p 8080:9000 \--restartalways -v /var/run/docker.sock:/var/run/docker.sock --privilegedtrue portainer/portainer 访问测试&#xff1a;外网…

Python_数据容器_元组tuple

一、元组tuple定义 为什么需要元组 列表是可以修改的&#xff0c;如果想要传递的信息不被篡改&#xff0c;列表就不适合了 元组和列表一样&#xff0c;都是可以封装多个不同类型的元素在内 最大的不同点在于&#xff1a; 元祖一旦定义完成&#xff0c;就不可修改 所以&am…

SpringBoot中使用JDBC

JDBC基础使用&#xff1a; JDBC基础使用_做测试的喵酱的博客-CSDN博客 一、SpringBoot使用JDBC&#xff0c;依赖 依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId&…

linux zookeeper kafka_2.12-2.2.0 集群

文章目录一、zookeeper服务搭建1. 下载2. 解压3. 创建目录4. 调整配置5. 配置myid6. 开放防火墙7.启动验证zk二、kafka集群搭建2.1. 下载软件2.2. 解压2.3. 配置2.5. 启动kafka三、测试验证3.1. 创建一个主题3.2. 发送消息3.3. 消费消息预先准备&#xff1a;上传软件至服务器19…

使用Avalonia跨Linux平台

Avalonia&#xff0c;读&#xff1a;阿瓦隆尼亚 这里的跨平台指的是&#xff0c;使用c#语言开发跨Linux平台。c#在Windows桌面开发中很强&#xff0c;但是在Linux桌面中&#xff0c;不能跨平台&#xff0c;Qt可以在Linux中跨平台&#xff0c;但是那是另外一门语言了。Avalonia…

计算机组成原理4小时速成:计算机运算方法,无符号数和有符号数,定点数和浮点数,移位运算,加减运算,乘法运算,原码,反码,补码

计算机组成原理4小时速成&#xff1a;计算机运算方法&#xff0c;无符号数和有符号数&#xff0c;定点数和浮点数&#xff0c;移位运算&#xff0c;加减运算&#xff0c;乘法运算&#xff0c;原码&#xff0c;反码&#xff0c;补码 2022找工作是学历、能力和运气的超强结合体&…

[激光原理与应用-16]:《激光原理与技术》-2- 光的本质(粒子、波动说、电磁波、量子)

目录 前言&#xff1a;“光” 一、光的微粒说 - 牛顿 二、光的波动说 - 托马斯杨 惠更斯 三、光是电磁波 - 麦克斯韦 四、光的波动说受到的挑战&#xff0c;光的波动说重新唤醒 五、光量子假说 - 爱因斯坦 六、光的理论综合 七、光的重要特性 7.1 光的相干性 7.2 相…

安装ideaIU-2022.1.4报错问题解决办法

原来版本是2020 现在因为要用到JDK17 而IDEA2020支持的JDK只能到14 所以我们现在在下载一个2022 .1.4 这时我们安装好后 会发现如下错误 原因分析&#xff1a; JetBrains 会将各个产品的这些文件也放到这个目录中&#xff0c;而新版本的 IntelliJ IDEA 在安装时遭遇了旧版本…

Web(二)html5基础-文本控制类标签(知识训练和编程训练)

web知识训练_html5_文本控制类标签 第1关_web知识训练_html5_文本控制类标签 -------------------------------------------- web编程训练_html5_文本控制类标签 第1关_html5_网页背景及标题段落标签 编程要求 根据前面的效果图&#xff0c;在右侧编辑器中的Begin - End区域…

10K涨到30K,5年大厂横跳,经验全在这两份Java面试精华总结里了

为了帮助大家跳槽成功多长点薪资&#xff0c;我这边给大家准备了两份面试资料。这两份资料可大有来头&#xff0c;已经帮助五位我认识的人进入大厂。所以说含金量还是很高的。 这两份资料可以让你体验到原有知识从破碎到重建&#xff0c;豁然开朗的过程。5年大厂横跳真实案例加…

数据库事务

1 概述 数据库的事务&#xff08;Transaction&#xff09;是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令。 事务把所有的命令作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这一组数据库命令要么同时成功&#xff0c;要么同时失败。 事务是一个不可…

前端开发——HTML5新增的客户端校验

1.使用校验属性执行校验 HTML5新增了表单的校验属性,如required、pattern等。 required:定义表单不能为空。属性值是required或者省略.pattern:定义表单满足正则表单式1.required属性 required属性用于不能为空。属性值是required或者省略. 代码如下&#xff1a; <form …

34 - 数组操作符的重载

---- 整理自狄泰软件唐佐林老师课程 1. 问题一 string类对象具备C方式字符串的灵活性吗&#xff1f;还能直接访问单个字符吗&#xff1f; 1.1 字符串类的兼容性 string类最大限度的考虑了C字符串的兼容性可以按照使用C字符串的方式使用string对象 1.2 编程实验&#xff1a…

BUUCTF Reverse/[GWCTF 2019]re3

main函数代码&#xff0c;这里改写了内存空间的属性&#xff0c;还是自解密 void __fastcall __noreturn main(int a1, char **a2, char **a3) {int i; // [rsp8h] [rbp-48h]char s[40]; // [rsp20h] [rbp-30h] BYREFunsigned __int64 v5; // [rsp48h] [rbp-8h]v5 __readfsqwo…

在Thymeleaf中格式化日期

1. 简介 在本文中&#xff0c;我们将介绍在百里香叶模板中格式化日期的方法。我们将使用 Thymeleaf 引擎中提供的特殊#calendars实用程序&#xff0c;该实用程序是为模板上的日期操作而创建的。 2. 使用实用程序类#calendar Thymeleaf带有一个名为#calendars的特殊实用程序类…

万字长文:从实践到原理说透Golang defer

本从以go-1.16版本源码为基础&#xff0c;介绍了defer关键字的使用规则、实现原理和优化路线&#xff0c;最后介绍了几种将近的使用场景。试图对 go defer 关键字应用到实现原理有一个全面的了解。 欢迎关注公众号闲余说 defer 概述 Go 提供关键字defer 处理延迟调用问题。在语…

超详细BootLoader原理分析

【摘要】本文详细地介绍了基于嵌入式系统中的 OS 启动加载程序 ―― BootLoader 的概念、软件设计的主要任务以及结构框架等内容。 在拿到空PCB板之后&#xff0c;硬件工程师首先会测试各主要线路是否通连&#xff08;各焊点是否有空焊、断接或短路的情况&#xff09;&#xff…

黑群辉+腾讯云+frp内网穿透

说明 家里用了移动宽带&#xff08;套餐便宜&#xff09;&#xff0c;结果没有了公网IP&#xff0c;只能想别的办法。 现在网上的方法大概三种 1. 第三方服务器代理&#xff1b; 要花钱&#xff0c;放弃! 2. frp穿透&#xff1b; 需要需要一台有公网IP的云服务器&#xff0…

线代——基础解系 vs 特征向量

基础解系 基础解系的概念是针对方程而言的&#xff1b;齐次线性方程组的解集的最大无关组称为齐次线性方程的基础解系&#xff1b;要求齐次线性方程组的通解&#xff0c;只需求出它的基础解系。 【例】 特征向量 特征向量和特征值满足关系式 AαλαA\alpha \lambda \alpha…

超融合兼顾医疗信创及 IT 云化转型的可行性分析

近期&#xff0c;中央出台财政贴息专项再贷款等“组合拳”政策&#xff0c;重点支持医疗、教育等关键行业的设备更新改造&#xff0c;同时央行将优先审核和支持对国产自主品牌的采购。这一系列动作表明&#xff0c;医疗行业的国产化替代&#xff08;即信息技术应用创新&#xf…