Java,从数组中查找第k个最大值

Java,从数组中查找第k个最大值,java,arrays,algorithm,min-heap,Java,Arrays,Algorithm,Min Heap,我接受了Facebook的采访,他们问了我这个问题 假设您有一个具有N个不同值的无序数组 $input=[3,6,2,8,9,4,5] 实现一个查找第k个最大值的函数 如果K=0,则返回9。如果K=1,则返回8 我所做的就是这个方法 private static int getMax(Integer[] input, int k) { List<Integer> list = Arrays.asList(input); Set<Integer> set =

我接受了Facebook的采访,他们问了我这个问题

假设您有一个具有N个不同值的无序数组

$input=[3,6,2,8,9,4,5]

实现一个查找第k个最大值的函数

如果K=0,则返回9。如果K=1,则返回8

我所做的就是这个方法

private static int getMax(Integer[] input, int k)
{
    List<Integer> list = Arrays.asList(input);
    Set<Integer> set = new TreeSet<Integer>(list);

    list = new ArrayList<Integer>(set);
    int value = (list.size() - 1) - k;

    return list.get(value);
}
private static int getMax(整数[]输入,int k)
{
List=Arrays.asList(输入);
集合=新树集合(列表);
列表=新阵列列表(集合);
int值=(list.size()-1)-k;
返回列表。获取(值);
}
我刚刚进行了测试,基于这个问题,该方法运行良好。然而,受访者说,
是为了让你的生活变得复杂!假设您的数组包含数百万个数字,那么您的列表将变得太慢。在这种情况下,您要做什么?

作为提示,他建议使用
minheap
。据我所知,堆的每个子值不应大于根值。所以,在这种情况下,如果我们假设3是根,那么6是它的子项,它的值比根的值大。我可能错了,但是您的想法以及它基于
min heap
的实现是什么?

编辑:检查此项以获得O(n)解决方案

您可能还可以利用来解决此问题:

public int findKthLargest(int[] nums, int k) {
        int p = 0;
        int numElements = nums.length;
        // create priority queue where all the elements of nums will be stored
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>();

        // place all the elements of the array to this priority queue
        for (int n : nums){
            pq.add(n);
        }

        // extract the kth largest element
        while (numElements-k+1 > 0){
            p = pq.poll();
            k++;
        }

        return p;
    }
public int findKthLargest(int[]nums,int k){
int p=0;
int numElements=nums.length;
//创建优先级队列,其中存储NUM的所有元素
PriorityQueue pq=新的PriorityQueue();
//将数组的所有元素放入此优先级队列
用于(整数n:nums){
pq.添加(n);
}
//提取第k个最大元素
while(numElements-k+1>0){
p=pq.poll();
k++;
}
返回p;
}
从Java:

实现说明:此实现为 enqueing和dequeing方法(
提供
轮询
删除()
添加
);
删除(对象)
包含(对象)
方法;检索方法的固定时间(
peek
元素
,和
大小


for循环运行了
n次
,上述算法的复杂性是
O(nlogn)

他实际上已经给出了完整的答案。不仅仅是一个暗示

您的理解基于
max heap
。不
min堆
。它的工作原理是不言自明的

min堆中,根具有最小值(小于其子级)

因此,您需要的是迭代数组,并在min heap中填充
K
元素。 一旦完成,堆将自动包含根上的最低值

现在,对于从数组中读取的每个(下一个)元素, ->检查该值是否大于最小堆的根。 ->如果是,则从最小堆中删除根,并向其添加值

遍历整个数组后,min heap的根将自动包含第k个最大元素


堆中的所有其他元素(精确地说是k-1元素)都将大于
k

,下面是使用java中的PriorityQueue实现Min-heap复杂性:
n*log k

import java.util.PriorityQueue;
公共级最大{
私有静态整数最大值(整数数组[],整数k){
优先级队列=新的优先级队列(k+1);
int i=0;

而(i如果数组/流中的元素数未知,则基于堆的解决方案是完美的。但是,如果它们是有限的,但仍然需要线性时间内的优化解决方案,该怎么办

我们可以使用快速选择,讨论

数组=[3,6,2,8,9,4,5]

让我们选择轴作为第一个元素:

枢轴=3(在第0个索引处)

现在对数组进行分区,所有小于或等于的元素都在左边,大于3的元素在右边,就像快速排序一样(在我的文章中讨论过)

所以在第一次通过之后-[2,3,,6,8,9,4,5]

pivot索引是1(即它是第二个最低的元素)。现在再次应用相同的过程

选择,6现在,在上一个轴之后的索引处的值-[2,3,4,5,6,8,9]

所以现在6在正确的位置


继续检查是否找到了合适的数字(每次迭代中第k个最大值或第k个最小值)。如果找到了,则继续。

对于
k
的常量值,一种方法是使用部分插入排序

(这假定值不同,但也可以很容易地修改以处理重复的值)

last_min=-inf
输出=[]
对于(0..k)中的i
最小值=+inf
用于输入数组中的值
如果值<最小值且值>最后一分钟
最小值=值
输出[i]=min
打印输出[k-1]
(这是伪代码,但应该很容易用Java实现)

总体复杂性为
O(n*k)
,这意味着当且仅当
k
为常数或已知小于
log(n)
时,它才能很好地工作


从正面看,这是一个非常简单的解决方案。从反面看,它不如堆解决方案有效。为什么不向面试官索要一个代码样本?在最小堆中,每个节点都小于或等于它的两个子节点。因此根节点应该是
2
,而不是
3
。一种可能的布局是tree
2->[3,4],3->[5,6],4->[8,9]
.Related-为什么要转换到树集并返回,而不仅仅是调用集合。排序?@immibis哦,是的,我不太熟悉:(我想从树集中删除所有重复项)
last_min = -inf
output = []
for i in (0..k)
    min = +inf
    for value in input_array
        if value < min and value > last_min
            min = value
    output[i] = min
print output[k-1]