LeetCode 堆(优先级队列) 相关题目

x33g5p2x  于2022-03-10 转载在 其他  
字(2.9k)|赞(0)|评价(0)|浏览(471)

第一题: 第 K 个最小的素数分数

LeetCode 786 : 第 K 个最小的素数分数
描述:
给你一个按递增顺序排序的数组 arr 和一个整数 k 。数组 arr 由 1 和若干 素数 组成,且其中所有整数互不相同。
对于每对满足 0 <= i < j < arr.lengthij ,可以得到分数 arr[i] / arr[j]
那么第 k 个最小的分数是多少呢? 以长度为 2 的整数数组返回你的答案, 这里 answer[0] == arr[i]answer[1] == arr[j]

解题思路:

  1. 求第K个最小的素数分数,先建立一个大小为k的大根堆.
  2. 然后遍历数组,让所有可能的分数遍历一次
  3. 首先让k个元素放入到堆中,
  4. 然后再遍历的时候,进行比较,小于堆顶元素的,出堆顶元素,然后入堆.
  5. 等到遍历结束,堆顶元素就是要得到的元素.
  6. 此题难点在于重写compare时如何进行比较,分数比较需要用到double,而return的是int.

代码实现:

  1. class Solution {
  2. public static int[] kthSmallestPrimeFraction(int[] arr, int k) {
  3. PriorityQueue<int[]> priorityQueue = new PriorityQueue<>(k,new Comparator<int[]>(){
  4. @Override
  5. public int compare(int[] o1, int[] o2) {
  6. double a1 = o1[0]*1.0 / o1[1];
  7. double a2 = o2[0]*1.0 / o2[1];
  8. int flg = 0;//用flg来返回
  9. if(a2 - a1 < 0) flg = -1;
  10. else if (a2 - a1 > 0) flg = 1;
  11. return flg;
  12. }
  13. });//大根堆.
  14. for (int i = 0; i < arr.length - 1; i++) {
  15. for (int j = i+1 ; j < arr.length; j++) {
  16. if(priorityQueue.size() < k){
  17. priorityQueue.offer(new int[]{arr[i],arr[j]});
  18. }else {
  19. double top = priorityQueue.peek()[0] * 1.0 / priorityQueue.peek()[1];
  20. double tmp = arr[i] * 1.0 / arr[j];
  21. if(tmp < top){//这里的比较也要double.
  22. priorityQueue.poll();
  23. priorityQueue.offer(new int[]{arr[i],arr[j]});
  24. }
  25. }
  26. }
  27. }
  28. return priorityQueue.peek();
  29. }
  30. }

第二题: 数据流中的第 K 大元素

LeetCode 703 : 数据流中的第 K 大元素
描述:
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:

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

解题思路:

  1. 建立一个大小为k的小根堆.
  2. add的时候,将val入队,如果堆没满直接入队,堆满了,需要判断之后再决定是否入队.
  3. add的类型为int,返回直接返回堆顶元素即可.

代码实现:

  1. class KthLargest {
  2. final PriorityQueue<Integer> priorityQueue;
  3. final int k ;
  4. public KthLargest(int k, int[] nums) {
  5. this.k = k;
  6. priorityQueue = new PriorityQueue<>(this.k, new Comparator<Integer>() {
  7. @Override
  8. public int compare(Integer o1, Integer o2) {
  9. return o1 - o2;
  10. }
  11. });
  12. for (int val:nums) {
  13. add(val);
  14. }
  15. }
  16. public int add(int val) {
  17. if(priorityQueue.size() < k){
  18. priorityQueue.offer(val);
  19. }else {
  20. if(val > priorityQueue.peek()){
  21. priorityQueue.poll();
  22. priorityQueue.offer(val);
  23. }
  24. }
  25. return priorityQueue.peek();
  26. }
  27. }

第三题: 前 K 个高频元素

LeetCode 347: 前 K 个高频元素
描述:
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

解题思路:

  1. 使用map,key值为数组出现的数据,value值记录key出现的次数.
  2. 使用优先级队列,构建一个大小为k的小根堆,比较的是value的大小.
  3. map添加的数据是有序的,所以直接遍历map,让数据入队.
  4. 当堆的大小 > k的时候,要弹出队顶元素,
  5. 遍历结束后,堆中的数据就是所需数据.
  6. 定义一个长度为k的数组,让key的值放入数组中即可.

代码实现:

  1. public int[] topKFrequent(int[] nums, int k) {
  2. int[] arr = new int[k];//长度为k的数组arr
  3. Map<Integer,Integer> map = new HashMap<>();
  4. //map记录数据出现的次数 key是数据,value是次数
  5. for (int i:nums) {
  6. map.put(i,map.getOrDefault(i,0)+1);
  7. }
  8. Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
  9. PriorityQueue<Map.Entry<Integer,Integer>> pq = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
  10. @Override
  11. public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
  12. return o1.getValue()-o2.getValue();//比较的是出现次数
  13. }
  14. });
  15. for (Map.Entry<Integer,Integer> entry:entrySet) {
  16. pq.offer(entry);//map是有序的,所以每次遍历只需要入队就可以了
  17. if(pq.size() > k){
  18. pq.poll();//堆大小>k 出队
  19. }
  20. }
  21. for (int i = k - 1; i >= 0; i--) {
  22. arr[i] = pq.poll().getKey();
  23. }//将数据添加到数组arr中
  24. return arr;
  25. }

相关文章