• leetcode-堆


    java中堆,不管是大根堆还是小根堆,都是优先队列PriorityQueue

    1.创建大根堆和小根堆

    (1)创建小根堆(堆顶元素最小):

    1. PriorityQueue queue=new PriorityQueue();
    2. //向堆里面添加元素
    3. queue.add(0);
    4. queue.add(1);
    5. queue.add(2);
    6. queue.add(3);
    7. queue.add(4);
    8. queue.add(5);
    9. queue.add(6);
    10. //输出堆中全部元素
    11. while(queue.isEmpty()==false)
    12. {
    13. System.out.println(queue.remove());
    14. }
    15. //输出:0,1,2,3,4,5,6,即小根堆每次弹出当前堆里面最小的元素

    (2)创建大根堆

    1. PriorityQueue queue=new PriorityQueue(
    2. {
    3. public int compare(Integer a,Integer b)
    4. {
    5. //这里如果是return a-b就是生成一个小根堆,return b-a就是生成一个大根堆
    6. return b-a;
    7. }
    8. }
    9. );
    10. //向堆里面添加元素
    11. queue.add(0);
    12. queue.add(1);
    13. queue.add(2);
    14. queue.add(3);
    15. queue.add(4);
    16. queue.add(5);
    17. queue.add(6);
    18. //输出堆中全部元素
    19. while(queue.isEmpty()==false)
    20. {
    21. System.out.println(queue.remove());
    22. }
    23. //输出6,5,4,3,2,1,0即大根堆每次弹出当前堆里面最大的元素

    事实上还有一种更简洁的创建大根堆的方式:

    1. PriorityQueue<Integer> queue=new PriorityQueue<Integer>(
    2. (a,b)->b-a
    3. )

    2.堆的常用方法:

    (1)通过索引获取堆里面的元素

     queue[0]=3, queue[1]=5,queue[2]=10........

    (2)向堆内添加元素:add

    弹出堆顶元素:remove

    返回堆顶元素(不删除):peek

    3.例题:用最大堆,最小堆来解决TopK问题:

    (1)小根堆:力扣703,找出数组中第k大的数

    暴力法的话是通过不了所有测试用例的

    1. class KthLargest
    2. {
    3. int k;
    4. ArrayList<Integer> a=new ArrayList();
    5. public KthLargest(int k, int[] nums)
    6. {
    7. this.k=k;
    8. for(int i:nums)
    9. {
    10. a.add(i);
    11. }
    12. }
    13. public int add(int val)
    14. {
    15. a.add(val);
    16. int[] result=new int[a.size()];
    17. int j=0;
    18. for(int temp:a)
    19. {
    20. result[j]=temp;
    21. j++;
    22. }
    23. Arrays.sort(result);
    24. return result[a.size()-k];
    25. }
    26. }

     小根堆法:

    1. class KthLargest
    2. {
    3. int k;
    4. // 创建一个小根堆(即堆顶元素最小)
    5. PriorityQueue<Integer> queue=new PriorityQueue<Integer>();
    6. //构造函数:传入k值和数组(后面调用add函数会往这个数组里面添加元素)
    7. public KthLargest(int k, int[] nums)
    8. {
    9. this.k=k;
    10. //这道题要维护一个size为k的堆
    11. //在堆的长度小于k之前,随便添加
    12. //当堆的长度等于k的时候,此时堆顶元素是这k个数中最小的
    13. //由于我们是想要找出数组中第k大的,所以要添加新的元素进堆中时,如果新的数比堆顶元素大,就可以进堆里面(先把堆顶元素弹出,然后再把这个新的元素添加进堆中),如果新的数不比堆顶元素大,就不添加进堆里
    14. for(int i=0;i<nums.length;i++)
    15. {
    16. if(queue.size()<k)
    17. {
    18. queue.add(nums[i]);
    19. }
    20. else
    21. {
    22. if(nums[i]>queue.peek())
    23. {
    24. queue.remove();
    25. queue.add(nums[i]);
    26. }
    27. }
    28. }
    29. }
    30. public int add(int val)
    31. {
    32. if(queue.size()<k) queue.add(val);
    33. else
    34. {
    35. if(val>queue.peek())
    36. {
    37. queue.remove();
    38. queue.add(val);
    39. }
    40. }
    41. return queue.peek();
    42. }
    43. }

    (2)大根堆的题:

    力扣1046 最后一块石头的重量

    1. class Solution
    2. {
    3. public int lastStoneWeight(int[] stones)
    4. {
    5. //构造一个大根堆
    6. PriorityQueue<Integer> queue=new PriorityQueue<Integer>((a,b)->b-a);
    7. //将数组里的元素放进大根堆
    8. for(int stone:stones)
    9. {
    10. queue.add(stone);
    11. }
    12. while(queue.size()>1)//只要堆里面的元素有两个以上
    13. {
    14. int a=queue.remove();//取出堆顶元素,即最大的元素
    15. int b=queue.remove();//继续取出堆顶元素,第二大的元素
    16. int c=Math.abs(a-b);
    17. queue.add(c);
    18. }
    19. //跳出循环,则堆里面只有一个元素了
    20. return queue.remove();
    21. }
    22. }

    (3)不止找一个数,而是找出若干个数(那就queue.remove()若干次,弹出若干次堆顶元素就行)

    力扣 最小的k个数

    暴力法:

    1. class Solution
    2. {
    3. public int[] getLeastNumbers(int[] arr, int k)
    4. {
    5. Arrays.sort(arr);
    6. int[] result=new int[k];
    7. for(int i=0;i<k;i++)
    8. {
    9. result[i]=arr[i];
    10. }
    11. return result;
    12. }
    13. }

    小根堆的方法:

    1. class Solution
    2. {
    3. public int[] getLeastNumbers(int[] arr, int k)
    4. {
    5. PriorityQueue<Integer> queue=new PriorityQueue();
    6. for(int i:arr)
    7. {
    8. queue.add(i);
    9. }
    10. int[] result=new int[k];
    11. for(int j=0;j<k;j++)
    12. {
    13. result[j]=queue.remove();
    14. }
    15. return result;
    16. }
    17. }

    (4)前k个高频元素

    力扣347

    1. class Solution
    2. {
    3. public int[] topKFrequent(int[] nums, int k)
    4. {
    5. HashMap<Integer,Integer> map=new HashMap();
    6. for(int num:nums)
    7. {
    8. map.put(num,map.getOrDefault(num,0)+1);
    9. }
    10. //构建一个特殊的小根堆,小根堆里面存的是hashmap的key,比较的依据是这这个key对应的value值,也就是说堆顶元素是这个堆中所有key中,对应的value最小的那个key
    11. PriorityQueue<Integer> queue=new PriorityQueue(
    12. new Comparator<Integer>()
    13. {
    14. @Override
    15. public int compare(Integer a, Integer b)
    16. {
    17. return map.get(a)-map.get(b);
    18. }
    19. }
    20. );//构建一个小根堆
    21. int size=0;
    22. //往小根堆里面添加key,在堆的容量没有达到k之前,随便加
    23. //一旦容量达到k,想要将key再加入堆,就必须这个key对应的value值要大于堆顶元素对应的value值
    24. for(int num:map.keySet())
    25. {
    26. if(size<k) queue.add(num);
    27. else//当小根堆的容量超过k
    28. {
    29. if(map.get(num)>map.get(queue.peek()))
    30. {
    31. queue.remove();
    32. queue.add(num);
    33. }
    34. }
    35. size++;
    36. }
    37. int[] result=new int[queue.size()];
    38. int temp=queue.size();
    39. for(int i=0;i<temp;i++)
    40. {
    41. result[i]=queue.remove();
    42. }
    43. return result;
    44. }
    45. }

  • 相关阅读:
    软件设计模式系列之二十三——策略模式
    Ribbon
    Qt全球峰会2023中国站 参会概要
    圈重点|等保2.0灾备方案怎么做?
    2022.11.10 vs每次都需要重新配置环境解决方案
    js连接mysql的使用方法
    【antdv】input实现搜索框获取清空输入值
    [ Linux Busybox ] flash_eraseall 命令解析
    python--列表list切分(超详细)
    Word控件Spire.Doc 【段落处理】教程(三):在 C#、VB.NET 中管理词标题以形成目录
  • 原文地址:https://blog.csdn.net/weixin_47414034/article/details/125550999