热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

算法TOPK(BFPRT算法)JAVA版本

一、背景在一大堆数中求其前k大或前k小的问题,简称TOP-K问题。而目前解决TOP-K问题最有效的算法即是BFPRT算法,其又称为中位数的中位数算法&

一、背景

在一大堆数中求其前k大或前k小的问题,简称TOP-K问题。而目前解决TOP-K问题最有效的算法即是BFPRT算法,其又称为中位数的中位数算法,该算法由Blum、Floyd、Pratt、Rivest、Tarjan提出,最坏时间复杂度为O(n)O(n)。

在首次接触TOP-K问题时,我们的第一反应就是可以先对所有数据进行一次排序,然后取其前k即可,但是这么做有两个问题: 
(1):快速排序的平均复杂度为O(nlogn)O(nlogn),但最坏时间复杂度为O(n2)O(n2),不能始终保证较好的复杂度。 
(2):我们只需要前k大的,而对其余不需要的数也进行了排序,浪费了大量排序时间。

除这种方法之外,堆排序也是一个比较好的选择,可以维护一个大小为k的堆,时间复杂度为O(nlogk)O(nlogk)。

那是否还存在更有效的方法呢?受到快速排序的启发,通过修改快速排序中主元的选取方法可以降低快速排序在最坏情况下的时间复杂度(即BFPRT算法),并且我们的目的只是求出前k,故递归的规模变小,速度也随之提高。下面来简单回顾下快速排序的过程,以升序为例: 
(1):选取主元(首元素,尾元素或一个随机元素); 
(2):以选取的主元为分界点,把小于主元的放在左边,大于主元的放在右边; 
(3):分别对左边和右边进行递归,重复上述过程。
原文链接:https://blog.csdn.net/laojiu_/article/details/54986553

    仅用荷兰国旗算法也能达到数学期望为O(N)的时间复杂度,但是也有可能存在O(N2)的最差情况,BFPRT就是在荷兰国旗算法的基础上,加入寻找一个好的中位数,让时间复杂度稳定在O(N)

二、算法套路

BFPRT算法套路
1. 对整个数组进行分组,每组5个数,不满5个的凑成最后一组
2.对每个组进行组内排序, 时间复杂度O(N)
    为什么时间复杂度O(N),解释:
    排序算法时间复杂度为O(NlogN), 当N等于5时候,即为O(1)
    对N/5个数组进行排序,所以时间复杂度为O(N)
3.拿出排序后的每个数组的中位数,组成一个新的N/5长度数组
4.递归掉BFPRT
5.拿到BFPRT的返回的num, 小于放左边,等于放中间,大于放右边。即快排里的荷兰国旗pattition算法。

伪代码:

int bfprt(int[] arr, int k){
    1.
    2.
    3.生成一个N/5大小的new_arr
    4.bfprt(new_arr, new_arr.length/2);
    5.
}

三、代码

public static int[] getMinKNumsByBFPRT(int[] arr, int k) {if (k <1 || k > arr.length) {return arr;}int minKth &#61; getMinKthByBFPRT(arr, k);int[] res &#61; new int[k];int index &#61; 0;for (int i &#61; 0; i !&#61; arr.length; i&#43;&#43;) {if (arr[i] &#61; pivotRange[0] && i <&#61; pivotRange[1]) {return arr[i];} else if (i pivotValue) {swap(arr, cur, --big);} else {cur&#43;&#43;;}}int[] range &#61; new int[2];range[0] &#61; small &#43; 1;range[1] &#61; big - 1;return range;}public static int getMedian(int[] arr, int begin, int end) {insertionSort(arr, begin, end);int sum &#61; end &#43; begin;int mid &#61; (sum / 2) &#43; (sum % 2);return arr[mid];}public static void insertionSort(int[] arr, int begin, int end) {for (int i &#61; begin &#43; 1; i !&#61; end &#43; 1; i&#43;&#43;) {for (int j &#61; i; j !&#61; begin; j--) {if (arr[j - 1] > arr[j]) {swap(arr, j - 1, j);} else {break;}}}}public static void swap(int[] arr, int index1, int index2) {int tmp &#61; arr[index1];arr[index1] &#61; arr[index2];arr[index2] &#61; tmp;}public static void printArray(int[] arr) {for (int i &#61; 0; i !&#61; arr.length; i&#43;&#43;) {System.out.print(arr[i] &#43; " ");}System.out.println();}public static void main(String[] args) {int[] arr &#61; { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };// sorted : { 1, 1, 1, 1, 2, 2, 2, 3, 3, 5, 5, 5, 6, 6, 6, 7, 9, 9, 9 }printArray(getMinKNumsByBFPRT(arr, 10));}

 


推荐阅读
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Java 类成员初始化顺序与数组创建
    本文探讨了Java中类成员的初始化顺序、静态引入、可变参数以及finalize方法的应用。通过具体的代码示例,详细解释了这些概念及其在实际编程中的使用。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • MQTT技术周报:硬件连接与协议解析
    本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ... [详细]
  • 本文介绍了如何在C#中启动一个应用程序,并通过枚举窗口来获取其主窗口句柄。当使用Process类启动程序时,我们通常只能获得进程的句柄,而主窗口句柄可能为0。因此,我们需要使用API函数和回调机制来准确获取主窗口句柄。 ... [详细]
author-avatar
国民男神-权志龙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有