Question
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4]
and k = 2, return 5.
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
本题难度Easy。有3种算法分别是: 排序、优先队列和快速排序
题意
题目说的是要第K大的元素,而不是第K大的数。
1、排序法
复杂度
时间 O(NlogN) 空间 O(1)
思路
排序后,倒数第K个就是答案。
代码
public class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length-k];
}
}
2、优先队列
复杂度
时间 O(NlogK) 空间 O(K)
思路
遍历数组时将数字加入优先队列(堆),一旦堆的大小大于k就将堆顶元素去除,确保堆的大小为k。遍历完后堆顶就是返回值。
附
优先队列就是最小堆,最小值在根节点。
代码
public class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> p = new PriorityQueue<Integer>();
for(int i = 0 ; i < nums.length; i++){
p.add(nums[i]);
if(p.size()>k) p.poll();
}
return p.poll();
}
}
3、快速排序
复杂度
时间 Avg O(N) Worst O(N^2) 空间 O(1)
思路
跟快速排序一个思路。先取一个枢纽值,将数组中小于枢纽值的放在左边,大于枢纽值的放在右边,最后把枢纽值放到分界点(具体请看被忽视的 partition 算法)。如果分界点后面有k-1个数,说明分界点的数就是第k个数;否则,如果分界点后的数大于k-1,则在右半边做同样的搜索;如果分界点后的数小于k-1,则在左半边做同样的搜索。
附
背景资料:被忽视的 partition 算法
实现快速排序的方法很多,最直观的就是用两个List,一个存放小于pivot,一个存放大于pivot,但是这样既低效又浪费空间,所以推荐使用partition算法。它的核心实际上就是双指针法:
begin
代表的是小于等于pivot
值的边界(不含begin
本身),end代表的是大于等于pivot的边界(不含end
本身),这样两指针逐渐往中间靠拢,最后begin==end
其位置就是pivot
所在点。
注意
- 第3行是
return quickSort(0,nums.length,nums,k);
而不是return quickSort(0,nums.length-1,nums,k);
- 第19行是
return quickSort(begin+1,r,arr,k);
而不是return quickSort(begin,r,arr,k);
代码
public class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSort(0,nums.length,nums,k);
}
private int quickSort(int l,int r,int[] arr, int k){
int pivot = arr[l],begin=l,end=r;
while(begin < end)
{
while(begin < end && arr[--end] >= pivot);
arr[begin] = arr[end];
while(begin < end && arr[++begin] <= pivot);
arr[end] = arr[begin];
}
int mid=begin;
arr[mid] = pivot;
if(arr.length-mid<k)
return quickSort(l,mid,arr,k);
else if(arr.length-mid>k)
return quickSort(mid+1,r,arr,k);
else
return pivot;
}
}