题目描述
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
解题思路
1、这道题如果是调用库函数,三行代码就求出
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length;
return nums[n - k ];
}
}
2、不使用库函数,使用快排思路
使用快排的思路:
(1)设置一个中心点pivot,将数组中小于或等于pivot的数放在数组的左边,将大于pivot的数放在数组的右边
Put numbers < pivot to pivot's left
Put numbers > pivot to pivot's right
(2)会有三种情况:(寻找第k个最大元素)
- 中心点pivot的索引值刚好为k,此时返回nums[k]
- 如果中心点pivot的索引值比k小,继续搜索中心点的左边
- 如果中心点pivot的索引值比k大,继续搜索中心点的右边
if indexOfPivot == k, return A[k]
else if indexOfPivot < k, keep checking left part to pivot
else if indexOfPivot > k, keep checking right part to pivot
3、代码逻辑:
求解第k个最大元素,这里使用快排的思路,可以理解为求解第(nums.length - k)
个最小元素。不需要 将数组全部排好序,只需要设置一个哨兵(中心点)。
代码快排
class Solution {
public int findKthLargest(int[] nums, int k) {
return findKthLargest(nums, 0, nums.length - 1, nums.length - k);
}
public int findKthLargest(int[] nums, int start, int end, int k){
int pivot = nums[end];
int left = start;
//for循环找出不大于nums[end]的数,其索引值为0-left
for(int i = start; i < end; i++){
if(nums[i] <= pivot)
swap(nums, left++, i);
}
swap(nums, left, end);
if(left == k)
return nums[left];
else if(left < k)
return findKthLargest(nums, left + 1, end, k);
else
return findKthLargest(nums, start, left - 1, k);
}
void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
代码2
class Solution {
public int findKthLargest(int[] nums, int k) {
final PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int val : nums){
pq.offer(val);
if(pq.size() > k)
pq.poll();
}
return pq.peek();
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int i = 0 ; i < nums.length; i++){
if(pq.size() < k)
pq.offer(nums[i]);
else if(nums[i] > pq.peek()){
pq.poll();
pq.offer(nums[i]);
}
}
return pq.peek();
}
}
代码3自己建堆
class Solution {
public int findKthLargest(int[] nums, int k) {
int heapSize = nums.length;
for(int i = 0; i < nums.length; i++){
heapInsert(nums, i);
}
for(int i = nums.length - 1; i >= nums.length - k + 1; --i){
swap(nums, 0, i);
--heapSize;
maxHeapify(nums, 0, heapSize);
}
return nums[0];
}
public void heapInsert(int[] arr, int index){
while(arr[index] > arr[(index - 1) / 2]){
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public void maxHeapify(int[] arr, int index, int size){
int left = index * 2 + 1;
while(left < size){
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
largest = arr[largest] > arr[index] ? largest : index;
if(largest == index)
break;
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
public void swap(int[] a, int i, int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
参考:https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60333/Concise-JAVA-solution-based-on-Quick-Select
https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60312/AC-Clean-QuickSelect-Java-solution-avg.-O(n)-time