1、题目描述
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
堆的定义:堆是一棵被完全填满的二叉树。
一棵高为h的完全二叉树有 到
个节点。
对数组中任一位置i上的元素,左儿子在2i上,右儿子在左儿子后2i+1。它的父节点在位置i/2上。
class Solution {
public int findKthLargest(int[] nums, int k) {
int heapSize = nums.length;
//buildHeap
//从最后一个父亲往前开始判断
for (int i = nums.length / 2 - 1; i >= 0; i--) {
percDown(nums, i, nums.length);
}
//删除最大值
for (int i = nums.length - 1; i >= nums.length - k + 1; i--) {
//最后一个值放到根的位置
swapReferences(nums, 0, i);
percDown(nums, 0, --heapSize);
}
return nums[0];
}
private static void swapReferences(int[] a, int oriIndex, int dstIndex) {
int temp = a[oriIndex];
a[oriIndex] = a[dstIndex];
a[dstIndex] = temp;
}
/**
* @param i 堆中的一个节点
* @return 左儿子
*/
private static int leftChild(int i) {
return 2 * i + 1;
}
/**
* 下滤
*
* @param a
* @param i
* @param n 堆大小
*/
private static void percDown(int[] a, int i, int n) {
int child;
int tmp;
for (tmp = a[i]; leftChild(i) < n; i = child) {
child = leftChild(i);
if (child != n - 1 && a[child] < a[child + 1]) {
//如果右儿子大于左儿子
child++;
}
if (tmp < a[child]) {
//如果父亲小于较大的子节点
a[i] = a[child];
} else {
break;
}
}
a[i] = tmp;
}
}