CT03-215.数组中第k大的元素
1.思路
寻找数组第k大的元素,因为是升序排序,索引第k大的元素对应的索引是n-k。
(1)快速选择算法
思想:基于partition的分区规则,缩小问题规模。随机选择一个pivot哨兵,比pivot小的元素放在右边,比pivot大的元素放在左边。target是我们要寻找的索引
1)如果p=target,直接返回
2)如果p<target,说明当前索引p比目标索引target小,要往右区间查找。
3)如果p>target,说明当前索引p比目标索引target大,要往左区间找。
快速选择算法的效率来自于它每次都能有效地“剪枝”,即排除掉一部分数组。
理想情况 (好 Pivot): 你选择的 pivot 正好是数组的中位数。分区后,左右两边的子数组大小基本相等。问题规模每次都减半,时间复杂度就是 n + n/2 + n/4 + …,最终结果是 O(n)。
最坏情况 (坏 Pivot): 你每次都选到了当前范围内的最大值或最小值。分区后,一个子数组有 n-1 个元素,另一个是空的。问题规模每次只减 1,时间复杂度就退化成了 n + (n-1) + (n-2) + …,最终结果是 O(n²)。
2)构造小根堆,堆顶元素就是最小的元素
堆是完全二叉树结构,基于优先队列实现。初始化一个最小堆(优先队列), PriorityQueue 默认就是最小堆,它会自动把最小的元素放在堆顶。
如果超过了 k,就移除堆顶的元素。
因为是最小堆,所以移除的永远是当前堆中最小的那个元素。
保证堆里永远只保留 k 个较大的元素。
2.代码实现
方法1:
方法2:
import java.util.PriorityQueue;public class solution2 {public int findKthLargest(int[] nums, int k) {PriorityQueue<Integer> pq = new PriorityQueue<>();//构造小根堆for (int num : nums) {pq.add(num);if (pq.size() > k)//如果当前小根堆的容量大于k,说明要移除一个元素{pq.poll();//弹出堆顶元素,因为堆顶元素存的是最小的元素}}return pq.peek();}public static void main(String[] args) {solution2 test=new solution2();int[] nums=new int[]{3,2,1,4,5};int res=test.findKthLargest(nums,2);System.out.println(res);}
}