Java,从数组中查找第k个最大值
我接受了Facebook的采访,他们问了我这个问题 假设您有一个具有N个不同值的无序数组 $input=[3,6,2,8,9,4,5] 实现一个查找第k个最大值的函数 如果K=0,则返回9。如果K=1,则返回8 我所做的就是这个方法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 =
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
。一种可能的布局是tree2->[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]