使用最小堆 (min-heap) 来解决该问题
代码逻辑:
-
初始化最小堆并插入前 K 个元素:
- 首先,将数组的前 K 个元素插入到堆中。此时,堆的大小为 K,堆顶元素是这 K 个元素中最小的。
-
遍历剩余的数组元素:
- 对于数组的其余元素(从第 K 个元素开始),我们逐个与堆顶元素进行比较。
- 如果当前元素比堆顶元素大,则说明它有可能是更大的元素之一,此时我们移除堆顶的最小元素,并将当前元素插入堆中。这样可以保持堆中总是存放着 K 个最大的元素。
-
返回堆顶元素:
- 最后,堆顶元素就是这 K 个最大的元素中最小的,也就是数组中的第 K 大元素。
代码示例:
class Solution {
public int findKthLargest(int[] nums, int k) {
// 初始化大小为K的最小堆
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);
// 先将前K个元素加入堆中
for(int i = 0; i < k; ++i) {
minHeap.offer(nums[i]);
}
// 遍历剩余的元素
for(int i = k; i < nums.length; ++i) {
// 如果当前元素大于堆顶元素,则替换堆顶元素
if(nums[i] > minHeap.peek()) {
minHeap.poll(); // 弹出堆顶最小元素
minHeap.offer(nums[i]); // 插入当前元素
}
}
// 堆顶元素即为第K大的元素
return minHeap.peek();
}
}
逻辑解释:
-
前 K 个元素入堆:在初始化阶段,先将前 K 个元素放入堆中,这一步确保了堆的初始状态是我们想要的(即包含前 K 个元素中的最小值)。
-
比较和替换:之后,遍历数组中剩余的元素,对于每个元素,我们都与堆顶的最小元素进行比较。只有当当前元素大于堆顶元素时,才会进行替换操作,这样可以确保堆中存放的始终是 K 个最大的元素。
-
返回结果:最终,当所有元素遍历完毕,堆顶元素就是这 K 个最大元素中的最小值,也就是数组中的第 K 大元素。
更容易理解的原因:
- 分步操作:先填充 K 个元素,然后逐步检查和替换剩余元素。将这两部分逻辑分开后,代码的意图非常明确。
- 显式的比较:通过
nums[i] > minHeap.peek()
来进行比较,显式地告诉读者当前元素是否应该被插入到堆中,这样逻辑显得更加直观。 - 清晰的堆维护:对于每一个新元素,如果它大于堆顶元素,就替换堆顶,使得堆始终维护着当前 K 个最大的元素。