首页 > 其他分享 >查找给定区间内第K大的元素

查找给定区间内第K大的元素

时间:2022-12-13 17:38:40浏览次数:45  
标签:num return int 元素 mid 给定 查找 数组 排序

查找给定区间内第K大的元素:

(一)方法一:最小堆:O( n*lg(k) )
(1)思想:
1.建立一个大小为k的最小堆
2.注意:是给定区间,堆中存放的是给定区间的元素,不是给定区间的元素不会存放。

说明:这个问题有些类似于n个数中查找最大的top(k)问题;

建立大小为k的最小堆,后续的n-k个数,每次和堆顶元素进行比较,比其大,则替换堆顶的值,调整最小堆;

调整最小堆的复杂度为o(lgk),所以整体复杂度为 O(n*lgk)

(二)方法二:快速排序之partion: O(n )
(1)思想:
快速排序的partion返回值i表示的是array[0~i-1]<=array[i]<=array[i+1~n-1];
如果i>k,则只需要在0~i-1区间继续partion,否则在i+1~n-1区间划分。

 

(2)解析:

有一个大小为 n的数组A[0,1,2,…,n-1],求其中第k大的数。

我们先取特例,令k=1,那么就是取最大的数,只要扫描一遍数组就可以确定该值,如果k=2,则扫描两边数组就可以确定第二大的数,依此类推下去,时间复杂度是O(k*n),如果k跟n是一个数量级,那么时间复杂度就是O(n*n)了,显然不是最优的解法。

 

考虑分治法,难点在于如何将该问题分解为两个子问题。

快速排序最基础的一步:

       随机取某一个数x,将其与数组末尾元素交换,然后将比其小的数交换至前,比其大的数交换至后。

这一步使某一数组的快速排序问题分解成两个子数组的排序问题,现在我们就依此来解决取第k大的数这个问题。

设数组下表从0开始,至n-1结束。

1、 随机取某个数,将其与数组末尾元素交换。

a)        idx=rand(0,n-1);生成[0,n-1]间的随机数。

b)        Swap(array[idx], array[n-1]);

2、 用末尾元素x,将比x小的数交换至前,比x大的数交换至后,并返回此时x在数组中的位置mid。

3、 如果mid==n-k,那么返回该值,这就是第k大的数。

如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数。

如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k的数。

 

(3)代码实现:

#include "iostream"
using namespace std;int random_partion(int *p, int n)
{
int idx=rand()%n;
swap(p[idx], p[n-1]);
int i=-1; //i表示最后一个小于p[n-1]的元素的位置
int j=0; //j用来扫描数组
for(j=0; j<n; j++)
{
//将小于p[n-1]的数交换到前半部分
if(p[j]<p[n-1])
{
swap(p[++i], p[j]);
}
}
swap(p[++i], p[n-1]);
return i;
}int getMaxK(int *p, int n, int k)
{
int mid;
if(k<=0)
return -1;
if(n<k)
return -1;
mid=random_partion(p, n); //对原数组进行一次划分
if(mid == n-k) //如果mid==n-k,那么返回该值,这就是第k大的数
return p[mid];
else if(mid<n-k)
return getMaxK(p+mid+1, n-mid-1, k); //如果mid<n-k,那么第k大的数在右半数组,而且仍然是第k大数
else
return getMaxK(p, mid, k-(n-mid)); //如果mid>n-k,那么第k大的数在左半数组,且在左半数组中是第k-(n-mid)大的数
}int main(void)
{
int num,a[] = {12012, 3, 945, 965, 66, 232, 65, 7, 8, 898, 56, 878, 170, 13, 5};
num=getMaxK(a, 15, 4);
printf("%d\n",num);
system("pause");
return 0;
}

(三)方法三:选择排序:O(k*n)

(四)伴随数组:O(n*lgn+n)

(1)范例:
如数组A[n]={1,3,2,5,4,7,6,9,8}
则下标在[3~6]范围内第3大的数为:即{5,4,7,6}范围内第3大的数为5.

(2)代码实现:

#include<iostream>
#include<algorithm>
using namespace std;struct node{
int num,data;//data表示的是元素的值,num代表的是元素最初的下标。bool operator < (const node &p) const{
return data < p.data;
}
};node p[100001];
int main()
{
int n=7;
int i,j,a,b,c;
for(i=1;i<=n;i++)//假定元素时从1开始存储。
{
scanf("%d",&p[i].data);
p[i].num = i;
}sort(p+1,p+1+n); //调用库函数sort完成排序,复杂度n*logn
scanf("%d %d %d",&a,&b,&c);
//[a,b]表示的是限定的区间,c表示要求的第k大的数。
for(i=1;i<=n;i++) //扫描一遍,复杂度n
{
if(p[i].num>=a && p[i].num<=b)
c--;
if(c == 0)
break;
}
printf("%d/n",p[i].data);
return 0;
}

(3)优点:

(1)适合多次查找给定区间内的第k大的值。
解析:只需要排序一次O(n*lgn),然后每次查找第k大 的值的查找时间都是O(n).
由于记录了最初数据的下标,所以没有破坏原始数据的顺序。

(五)给定区间内直接排序:O(m*lgm) (m为给定区间大小)

(1)缺点:无法多次查找给定区间内的第k大的值,因为排序后破坏了原始的数据顺序。

 

标签:num,return,int,元素,mid,给定,查找,数组,排序
From: https://blog.51cto.com/u_15911260/5934905

相关文章

  • #yyds干货盘点# 名企真题专题: 二分查找
    1.简述:描述对于一个有序数组,我们通常采用二分查找的方式来定位某一元素,请编写二分查找的算法,在数组中查找指定元素。给定一个整数数组A及它的大小n,同时给定要查找的元素val,......
  • LeetCode 215_数组中的第K个最大元素
    LeetCode215:数组中的第K个最大元素题目给定整数数组nums和整数k,请返回数组中第k个最大的元素。请注意,你需要找的是数组排序后的第k个最大的元素,而不是第k个......
  • CAD查找替换文字时如何使用通配符?CAD通配符使用技巧(一)
    通配符是一种特殊语句,主要有星号和问号,用来模糊搜索文件。那么,CAD查找替换文字时如何使用通配符呢?本文小编就来给大家分享一下浩辰CAD软件中查找替换文字时使用通配符的操......
  • UE4读取scv文件 -- 数据驱动游戏性元素
    官方文档链接:​​http://docs.unrealengine.com/latest/CHN/Gameplay/DataDriven/index.html​​略懒,稍微麻烦重复的工作,总希望能找人帮忙一起做,但是有人对于稍微一点点的......
  • 四种二分查找法模板
    publicclassBinarySearch{publicstaticvoidmain(String[]args){int[]arr={1,2,3,3,3,4,5,5,7};intupper1=floor_lower(arr,3);......
  • 剑指offer82:含有重复元素集合的组合
    题目:给定一个可能有重复数字的整数数组candidates和一个目标数target,找出candidates中所有可以使数字和为target的组合。candidates中的每个数字在每个组合中只......
  • 剑指offer81:允许重复选择元素的组合
    题目:给定一个无重复元素的正整数数组candidates和一个正整数target,找出candidates中所有可以使数字和为目标数target的唯一组合。candidates中的数字可以无限制......
  • 剑指offer84:包含重复元素集合的全排列
    题目:给定一个可包含重复数字的整数集合nums,按任意顺序返回它所有不重复的全排列。1.输入:nums=[1,1,2]输出:[[1,1,2],[1,2,1],[2,1,1]]2.输入:nums=[1,2,3]输出......
  • 剑指offer80:包含k个元素的组合
    **题目:**给定两个整数n和k,返回1…n中所有可能的k个数的组合。输入:n=4,k=2输出:[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],]输入:n=1,k=1输......
  • 为什么总是应该考虑给定 List 的初始大小
    在.Net技术中,使用List<>来存储数据是很常见的。List<>是一个可以动态增长的泛型集合类型,可以存储任何类型的数据。但是,在实际使用中,很多人并不注意给定List<>的初......