• 【数据结构与算法 | 堆篇】力扣215


    1. 力扣215 : 数组中的第k个最大元素

    (1). 题

    给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

    请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

    你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

    示例 1:

    输入: [3,2,1,5,6,4], k = 2
    输出: 5
    

    示例 2:

    输入: [3,2,3,1,2,4,5,5,6], k = 4
    输出: 4
    

    提示:

    • 1 <= k <= nums.length <= 105
    • -104 <= nums[i] <= 104

    (2). 思路1

    工具类直接无脑秒了.

    (3). 解1

    1. class Solution {
    2. public int findKthLargest(int[] nums, int k) {
    3. Arrays.sort(nums);
    4. return nums[nums.length - k];
    5. }
    6. }

    (4). 思路2

    利用优先队列再秒. 使用了比较器,每次poll出的是数值最大的元素.

    (5). 解2

    1. class Solution {
    2. public int findKthLargest(int[] nums, int k) {
    3. PriorityQueue pq = new PriorityQueue<>((o1, o2) -> {
    4. return o2 - o1;
    5. });
    6. for (int i = 0; i < nums.length; i++) {
    7. pq.offer(nums[i]);
    8. }
    9. for (int i = 0; i < k - 1; i++) {
    10. pq.poll();
    11. }
    12. return pq.peek();
    13. }
    14. }

    (6). 思路3

    构造大顶堆,思路如上. 不加比较器的优先级队列底层就是用小顶堆实现的.

    (7). 解3

    1. class Solution {
    2. public int findKthLargest(int[] nums, int k) {
    3. Heap heap = new Heap(nums.length);
    4. heap.heapify(nums);
    5. return heap.sort(k);
    6. }
    7. }
    8. //大顶堆
    9. class Heap{
    10. //堆的大小
    11. private int size;
    12. int[] heap;
    13. public Heap(int capacity) {
    14. heap = new int[capacity];
    15. }
    16. //堆化
    17. public void heapify(int[] nums) {
    18. for (int i = 0; i < nums.length; i++) {
    19. heap[i] = nums[i];
    20. }
    21. size = nums.length;
    22. //从最后一个非叶子节点开始, 下沉
    23. for (int parent = (size - 1) / 2; parent >= 0; parent--) {
    24. int leftChild = parent*2+1;
    25. int rightChild = parent*2+2;
    26. int max = parent;
    27. //如果左孩子存在, 而且左孩子比父亲还要大
    28. if (leftChild < size && heap[leftChild] > heap[max]) {
    29. max = leftChild;
    30. }
    31. //如果右孩子存在, 而且左孩子比父亲和左孩子还要大
    32. if (rightChild < size && heap[rightChild] > heap[max]){
    33. max = rightChild;
    34. }
    35. if (max != parent) {
    36. down(parent);
    37. }
    38. }
    39. }
    40. public void down(int parent) {
    41. int leftChild = parent*2+1;
    42. int rightChild = parent*2+2;
    43. int max = parent;
    44. if (leftChild < size && heap[leftChild] > heap[max]) {
    45. max = leftChild;
    46. }
    47. if (rightChild < size && heap[rightChild] > heap[max]){
    48. max = rightChild;
    49. }
    50. if (max != parent) {
    51. swap(max, parent);
    52. down(max);
    53. }
    54. }
    55. private void swap(int max, int parent) {
    56. int temp;
    57. temp = heap[max];
    58. heap[max] = heap[parent];
    59. heap[parent] = temp;
    60. }
    61. public int sort(int k) {
    62. int n = size;
    63. while (size > 1){
    64. swap(0, size-1);
    65. size--;
    66. down(0);
    67. }
    68. size = n;
    69. return heap[size - k];
    70. }
    71. }

    2. 力扣703 : 数据流中的第k大元素

    (1). 题

    设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

    请实现 KthLargest 类:

    • KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
    • int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

    示例:

    输入:
    ["KthLargest", "add", "add", "add", "add", "add"]
    [[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
    输出:
    [null, 4, 5, 5, 8, 8]
    
    解释:
    KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
    kthLargest.add(3);   // return 4
    kthLargest.add(5);   // return 5
    kthLargest.add(10);  // return 5
    kthLargest.add(9);   // return 8
    kthLargest.add(4);   // return 8
    

    提示:

    • 1 <= k <= 104
    • 0 <= nums.length <= 104
    • -104 <= nums[i] <= 104
    • -104 <= val <= 104
    • 最多调用 add 方法 104 次
    • 题目数据保证,在查找第 k 大元素时,数组中至少有 k 个元素

    (2). 思路

    思路都在题解上.

    (3). 解

    1. public class KthLargest {
    2. //优先队列的底层实现是小顶堆, 所以将该堆的大小维持在k个长度时,
    3. //取堆首元素, 就是堆第k大的元素, 因为堆下面的元素都大于堆首
    4. PriorityQueue pq = new PriorityQueue<>();
    5. int k1;
    6. public KthLargest(int k, int[] nums) {
    7. //add方法中需要使用k, 所以用k1记录k的值
    8. k1 = k;
    9. int i;
    10. //如果k <= nums.length, 分成两个部分判断
    11. //如果k > nums.length, 力扣该题9个案例似乎都是这种情况
    12. //只有一种情况, 即k比nums数组的长度大一个长度, 所以add以后k就可以取到第k大的元素
    13. if (k <= nums.length) {
    14. for (i = 0; i < k; i++) {
    15. pq.offer(nums[i]);
    16. }
    17. for (i = k ; i < nums.length; i++) {
    18. //如果该数组的元素要比堆首元素要大,
    19. //将堆首元素移除, 加入该数组元素.
    20. //堆首元素就是新的第k大的元素
    21. if (nums[i] > pq.peek()) {
    22. pq.poll();
    23. pq.offer(nums[i]);
    24. }
    25. }
    26. } else {
    27. for (i = 0; i < nums.length; i++) {
    28. pq.offer(nums[i]);
    29. }
    30. }
    31. }
    32. public int add(int val) {
    33. //此时k比堆的大小要大一个, 直接将该元素入堆即可
    34. if (k1 > pq.size()) {
    35. pq.offer(val);
    36. } else {
    37. if (val > pq.peek()) {
    38. pq.poll();
    39. pq.offer(val);
    40. }
    41. }
    42. return pq.peek();
    43. }
    44. }
  • 相关阅读:
    不就是Java吗之 String类 PartII
    Sentinel
    Java如何对接阿里云盘API
    【Axure高保真原型】日历日期原型模板
    k8s-----17、集群安全机制
    修复 JavaScript 错误的四种方法
    1704. 判断字符串的两半是否相似
    【C++面向对象】13. 接口 / 抽象类*
    问界M7的诸多优点(自动驾驶走进我们的生活二)
    二、VXLAN BGP EVPN基本原理
  • 原文地址:https://blog.csdn.net/2301_80912559/article/details/139397784