相关介绍:

 给定一个数组,找出该数组中第n大的元素的值。其中,1<=n<=length。例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9。解决该问题的算法有三种。依据其时间复杂度的高低,分别对其进行讲解

第一种:时间复杂度为O(NlogN)

 解决该问题,容易想到的一个办法是,先对数组按元素值从大到小的方式进行排序,之后选取出其符合要求的元素并返回其值。由基于比较的排序算法的时间复咋读,其下界为NlogN,为此,解决该问题的时间复杂度为O(NlogN)。

示例代码:

/**
* 思路:排序数组,并寻找一个原本乱序的数组中的第th大的元素
* 平均时间复杂度视具体的排序算法而定,一般是O(nlogn)
* @param th 第th大的元素,即要找的那个元素在数组中的真实的下标的元素索引
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*/
public int sort(int th)
{
Arrays.sort(array);
return array[th];
}

第二种:平均情况下时间复杂度为O(N)

 该算法运用了快速排序的思想,由于在快速排序的思想中,每次确定一个数组中元素的正确位置,为此,可以通过比较每次查找出来的元素在数组中的正确位置和想要进行查找的位置的元素之间的关系,就可排除掉一部分元素,从而逼近答案。在最优的情况下,每次能够排除掉N/2个数组元素,为此,可以根据主定理法计算得出,其平均情况下,时间复杂度为O(N)

示例代码:

/**
* 思路:使用快速排序的思想,去寻找一个乱序的数组中的第th大的元素
* 由于快速排序的思想中,每次确定一个元素在数组中的正确位置,为此,通过比较每次
* 查找出来的元素在数组中的正确位置和想要进行查找的位置的元素之间的关系,可以排除
* 掉一部分元素,从而逼近答案。在最优的情况下,每次能够排除掉N/2个数组元素
* 平均时间复杂度为O(n)
* @param th 第th大的元素,即要找的那个元素在数组中的真实的下标的元素索引
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*/
public int QuicklySortedMind(int th,int low,int high)
{
int lows=low;
int highs=high;
//选择该元素为基准元素
int midNumber=array[low];
//以下为快速排序部分,用于将元素midNumber的值插入到数组的正确位置中
while(low<high)
{
while(array[high]>midNumber&&low<high)
high--;
if(low<high)
{
array[low]=array[high];
}
while(array[low]<midNumber&&low<high)
low++;
if(low<high)
{
array[high]=array[low];
}
}
array[low]=midNumber;
//用于递归的寻找第n大的元素
//当找到的那个中间的元素为要找的第th大的元素的时候,将其直接进行返回
//ps:关键点在于,low的值即使是递归查找出来的,其依然为数组的绝对索引值
if(th==low)
return array[low];
//当找到的元素的位置在想要找的元素的位置的左边时,从右边继续寻找
else if(th>low)
return QuicklySortedMind(th,low+1,highs);
//当找到的元素的位置在想要找的元素的位置的右边时,从左边继续寻找
else
return QuicklySortedMind(th,lows,low-1);
}

第三种:时间复杂度为O(N)

 该算法根据以上快速排序的思想进行改进,由于每次选择的元素找到其在数组中的位置时,其不一定能够恰好排除掉N/2个元素,在最坏的情况下,每次只能排除掉一个数组元素。为此,第二种解决办法在最坏的情况下可能达到O(N^2)。而该算法,就是基于解决不能够排除掉N/2个数组元素的情况下提出的。在数组元素中找到一个划分基准,使其按照这个基准所划分出的两个子数组的长度都至少为原数组长度的v倍(0< v< 1),则在最坏情况下,其也能用O(N)的时间完成任务。该算法的基本思路如下:对数组中的元素进行分组(每组元素的个数为5个),之后找到各组中的中位数,之后再找到中位数的中位数,将中位数的中位数那个元素根据快速排序的思想,找到其在数组中的正确的位置,使得其每次都能够排除掉一定数量的数组元素,从而逼近答案。

示例代码如下:

/**
* 采用线性时间选择的算法找出第th大的元素的值
* 线性时间选择算法的思想为:
* 线性时间选择算法是对上面那个基于快速选择排序算法查找第n大的数组元素的改进。具体思想如下:
* 对数组中的元素进行分组(每组元素的个数为5个),之后找到各组中的中位数,之后再找到中位数的中位数
* 将中位数的中位数那个元素根据快速排序的思想,找到其在数组中的正确的位置
* 使得其每次都能够排除掉一定的数组元素,从而逼近答案
* @param th 第th大的元素
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*
*/
public int LinedSelectFind(int th,int low,int high)
{
//当数组元素个数小于5个的时候,即只有一组元素的时候,将其进行排序,之后直接返回
if(high-low<5)
{
Arrays.sort(array,low,high);
return array[low+th-1];
}
//变量i用于控制数组元素分组的迭代
//每组5个元素,为此,总共的组别数目为(high-low-4)/5组(舍弃掉数组元素不足5个的组别,不考虑元素个数不足5个的分组)
//其等价与i<(high-low)/5
for(int i=0;i<=(high-low-4)/5;i++)
{
//变量s为每组元素的第一个元素的下标(即索引),t为每组元素的最后一个元素的下标(即索引)
int s=low+5*i,t=s+4;
/*for(int j=0;j<3;j++)
{*/
//用于排序s到t之间的数组中的每组元素的前三个数组元素
Arrays.sort(array,s,t-2);
//用于将每组元素中的中位数按照各组之间的区别,
//在原数组(low到high之间的数组)中从头开始排,即原数组(low到high之间的数组)中
// 前(high-low-4)/5个元素为各个分组的中位数
swap(array,low+i,s+2);
/*
}
*/
}
//选择出中位数的中位数,其中在low到low+(high-low-4)/5这个范围内,其中、中位数为第(high-low+6)/10大的元素
int x=LinedSelectFind((high-low+6)/10,low,low+(high-low-4)/5);
//变量i为中位数的中位数那个数在数组中所在的下标位置,变量j为相对low到high这个范围的数组,元素x为其第几大的元素
int i=partition(low,high,x),j=i-low+1;
//进行递归查找,直到数组元素小于5个的时候
//当th在j的左边或者相等的时候,在low到i之间继续寻找第th大的元素
if(th<=j)
return LinedSelectFind(th,low,i);
//当th在j的右边的时候,在i+1到high之间,继续寻找第th-j大的元素
else
return LinedSelectFind(th-j,i+1,high);
}
//将元素x放置到p到r之间的数组元素的正确位置,并返回元素x所在的下标
private int partition(int p,int r,int x)
{
int i=p,j=r+1;
while(true)
{
while(array[++i]<x&&i<r);
while(array[--j]>x);
if(i>=j)
break;
swap(array,i,j);
}
array[p]=array[j];
array[j]=x;
return j;
}
//交换数组array中的下标为index1和index2的两个数组元素
private void swap(int[] array,int index1,int index2)
{
int temp=array[index1];
array[index1]=array[index2];
array[index2]=temp;
}

代码汇总如下:

package other;

import java.util.Arrays;

/**
* 该类用于演示在一个无序的数组中寻找第n大的数的三个算法
* @author 学徒
*
*/ public class FindTHNumber
{
int[] array=null;
public static void main(String[] args)
{
FindTHNumber n=new FindTHNumber();
n.array=new int[]{1,3,2,4,5,6};
int low=0;
int high=n.array.length-1;
int th=6;
System.out.println(n.QuicklySortedMind(th-1, low, high));
System.out.println(n.sort(th-1));
System.out.println(n.LinedSelectFind(th, low, high));
}
/**
* 思路:排序数组,并寻找一个原本乱序的数组中的第th大的元素
* 平均时间复杂度视具体的排序算法而定,一般是O(nlogn)
* @param th 第th大的元素,即要找的那个元素在数组中的真实的下标的元素索引
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*/
public int sort(int th)
{
Arrays.sort(array);
return array[th];
}
/**
* 思路:使用快速排序的思想,去寻找一个乱序的数组中的第th大的元素
* 由于快速排序的思想中,每次确定一个元素在数组中的正确位置,为此,通过比较每次
* 查找出来的元素在数组中的正确位置和想要进行查找的位置的元素之间的关系,可以排除
* 掉一部分元素,从而逼近答案。在最优的情况下,每次能够排除掉N/2个数组元素
* 平均时间复杂度为O(n)
* @param th 第th大的元素,即要找的那个元素在数组中的真实的下标的元素索引
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*/
public int QuicklySortedMind(int th,int low,int high)
{
int lows=low;
int highs=high;
//选择该元素为基准元素
int midNumber=array[low];
//以下为快速排序部分,用于将元素midNumber的值插入到数组的正确位置中
while(low<high)
{
while(array[high]>midNumber&&low<high)
high--;
if(low<high)
{
array[low]=array[high];
}
while(array[low]<midNumber&&low<high)
low++;
if(low<high)
{
array[high]=array[low];
}
}
array[low]=midNumber;
//用于递归的寻找第n大的元素
//当找到的那个中间的元素为要找的第th大的元素的时候,将其直接进行返回
//ps:关键点在于,low的值即使是递归查找出来的,其依然为数组的绝对索引值
if(th==low)
return array[low];
//当找到的元素的位置在想要找的元素的位置的左边时,从右边继续寻找
else if(th>low)
return QuicklySortedMind(th,low+1,highs);
//当找到的元素的位置在想要找的元素的位置的右边时,从左边继续寻找
else
return QuicklySortedMind(th,lows,low-1);
}
/**
* 采用线性时间选择的算法找出第th大的元素的值
* 线性时间选择算法的思想为:
* 线性时间选择算法是对上面那个基于快速选择排序算法查找第n大的数组元素的改进。具体思想如下:
* 对数组中的元素进行分组(每组元素的个数为5个),之后找到各组中的中位数,之后再找到中位数的中位数
* 将中位数的中位数那个元素根据快速排序的思想,找到其在数组中的正确的位置
* 使得其每次都能够排除掉一定的数组元素,从而逼近答案
* @param th 第th大的元素
* @param low 数组的元素下标,表示需要进行排序的数组元素的开始的下标
* @param high 数组元素的下标,表示需要进行排序的数组元素的结束的下标
* @return 返回第th大的那个数组元素
*
*/
public int LinedSelectFind(int th,int low,int high)
{
//当数组元素个数小于5个的时候,即只有一组元素的时候,将其进行排序,之后直接返回
if(high-low<5)
{
Arrays.sort(array,low,high);
return array[low+th-1];
}
//变量i用于控制数组元素分组的迭代
//每组5个元素,为此,总共的组别数目为(high-low-4)/5组(舍弃掉数组元素不足5个的组别,不考虑元素个数不足5个的分组)
//其等价与i<(high-low)/5
for(int i=0;i<=(high-low-4)/5;i++)
{
//变量s为每组元素的第一个元素的下标(即索引),t为每组元素的最后一个元素的下标(即索引)
int s=low+5*i,t=s+4;
/*for(int j=0;j<3;j++)
{*/
//用于排序s到t之间的数组中的每组元素的前三个数组元素
Arrays.sort(array,s,t-2);
//用于将每组元素中的中位数按照各组之间的区别,
//在原数组(low到high之间的数组)中从头开始排,即原数组(low到high之间的数组)中
// 前(high-low-4)/5个元素为各个分组的中位数
swap(array,low+i,s+2);
/*
}
*/
}
//选择出中位数的中位数,其中在low到low+(high-low-4)/5这个范围内,其中、中位数为第(high-low+6)/10大的元素
int x=LinedSelectFind((high-low+6)/10,low,low+(high-low-4)/5);
//变量i为中位数的中位数那个数在数组中所在的下标位置,变量j为相对low到high这个范围的数组,元素x为其第几大的元素
int i=partition(low,high,x),j=i-low+1;
//进行递归查找,直到数组元素小于5个的时候
//当th在j的左边或者相等的时候,在low到i之间继续寻找第th大的元素
if(th<=j)
return LinedSelectFind(th,low,i);
//当th在j的右边的时候,在i+1到high之间,继续寻找第th-j大的元素
else
return LinedSelectFind(th-j,i+1,high);
}
//将元素x放置到p到r之间的数组元素的正确位置,并返回元素x所在的下标
private int partition(int p,int r,int x)
{
int i=p,j=r+1;
while(true)
{
while(array[++i]<x&&i<r);
while(array[--j]>x);
if(i>=j)
break;
swap(array,i,j);
}
array[p]=array[j];
array[j]=x;
return j;
}
//交换数组array中的下标为index1和index2的两个数组元素
private void swap(int[] array,int index1,int index2)
{
int temp=array[index1];
array[index1]=array[index2];
array[index2]=temp;
}
}

回到目录|·(工)·)

K:找寻数组中第n大的数组元素的三个算法的更多相关文章

  1. 无序数组中第Kth大的数

    题目:找出无序数组中第Kth大的数,如{63,45,33,21},第2大的数45. 输入: 第一行输入无序数组,第二行输入K值. 该是内推滴滴打车时(2017.8.26)的第二题,也是<剑指of ...

  2. 求一无序数组中第n大的数字 - 快速选择算法

    逛别人博客的时候,偶然看到这一算法题,顺便用C++实现了一下. 最朴素的解法就是先对数组进行排序,返回第n个数即可.. 下面代码中用的是快速选择算法(不晓得这名字对不对) #include <v ...

  3. extract_by_one 根据二维数组中某字段来提取数组信息,查看有无重复信息

    public function tt(){ $param = array( array ( 'hykno' => '2222222-CB', 'tcdk_fid' => '458B6D70 ...

  4. 算法练习之合并两个有序链表, 删除排序数组中的重复项,移除元素,实现strStr(),搜索插入位置,无重复字符的最长子串

    最近在学习java,但是对于数据操作那部分还是不熟悉 因此决定找几个简单的算法写,用php和java分别实现 1.合并两个有序链表 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两 ...

  5. JavaScript数组中出现的次数最多的元素

    var arr = [1,-1,2,4,5,5,6,7,5,8,6]; var maxVal = arr[0]; // 数组中的最大值 var minVal = arr[0]; // 数组中的最小值 ...

  6. 《剑指offer》第五十三题(数组中数值和下标相等的元素)

    // 面试题53(三):数组中数值和下标相等的元素 // 题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的.请编程实 // 现一个函数找出数组中任意一个数值等于其下标的元素.例如,在数组{ ...

  7. LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)

    题目链接:https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/#/description 给定一个已经排好序的数组 ...

  8. javascript 数组中出现的次数最多的元素

    javascript 数组中出现的次数最多的元素 var arr = [1,-1,2,4,5,5,6,7,5,8,6]; var maxVal = arr[0]; // 数组中的最大值 var min ...

  9. 剑指offer——58数组中数值和下标相等的元素

    题目三: 数组中数值和下标相等的元素. 假设一个单调递增的数组里的每个元素都是整数并且是唯一的.请编程实现一个函数,找出数组中任意一个数值等于其下标的元素.例如,在数组{-3,-1,1,3,5}中,数 ...

随机推荐

  1. (二)SSO之CAS框架单点退出,自定义退出界面.

    用CAS的退出,只能使用它自己的那个退出界面,如果有这样的要求, 要求退出后自动跳转到登录界面, 该如何做呢?下面这篇文章实现了退出后可以自定义跳转界面.  用了CAS,发现退出真是个麻烦事,退出后跳 ...

  2. Leetcode 102 二叉树的层次遍历 Python

    二叉树的层次遍历 给定一个二叉树,返回其按层次遍历的节点值. (即逐层地,从左到右访问所有节点). 例如: 给定二叉树: [3,9,20,null,null,15,7],   3   / \ 9 20 ...

  3. python 对mongodb进行压力测试

    最近对mongoDB数据库进行性能分析,需要对数据库进行加压. 加压时,最初采用threading模块写了个多线程程序,测试的效果不理想. 单机读数据库每秒请求数只能达到1000次/s.而开发的jav ...

  4. 从源码的角度再学「Thread」

    前言 Java中的线程是使用Thread类实现的,Thread在初学Java的时候就学过了,也在实践中用过,不过一直没从源码的角度去看过它的实现,今天从源码的角度出发,再次学习Java Thread, ...

  5. 2016级算法第六次上机-D.AlvinZH的学霸养成记V

    1081 AlvinZH的学霸养成记V 思路 中等题,计算几何. 这是一个排序问题,按极角排序.可以转化为叉积的应用,对于点A和B,通过叉积可以判断角度大小,共线时再判断距离. 叉积的应用.OA × ...

  6. Redis学习笔记(6)——SpringDataRedis入门

    一.SpringDataRedis简介 Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, ...

  7. django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')

    环境介绍 Django (2.1)  Python 3.5.5 mysqlclient (1.4.2.post1) Mysql 5.6.28 RHEL 7.3 在migrate时候报错 model代码 ...

  8. Redis服务挂掉后,重启时闪退

    这个时候去进程管理器里找一个 redisservice.exe 的进程..杀死他  杀死他  杀死他!!! 整理领结,嘬口咖啡, 嗯... 然后再来启动服务..

  9. 【ORACLE】oracle 日志文件管理

    修改Oracle重做日志文件大小 创建新的日志组1 删除旧的日志组0(旧的日志组状态需要是INACTIVE) 创建新的日志组2,组名为旧的日志组0的组名 删除日志组1 ---------------- ...

  10. 数据库其他注入思路 - 万能密码 - cookie注入 -搜索型注入

    另类登录注入形式: 经常有一类验证(ASP,PHP,JSP均存在),先判断user是否存在,ASP为例子:"select password from admin where user_nam ...