力扣347,BM46,BM47(堆)

347、前k个高频元素 

基本思想:

要统计元素出现频率

对频率排序

找出前K个高频元素

具体实现:

对频率进行排序,使用优先级队列

https://blog.csdn.net/qq_35326718/article/details/72866180

1.满二叉树除了叶子节点,其余所有节点都有左右孩子节点

完全二叉树的非叶子节点,孩子一定要按照从左到右的顺序

完全二叉树的同一层上,前面的节点没有孩子节点,后面的节点就不能有孩子节点

每个节点必须先有左节点才能有右节点

 

完全二叉树优点:从任意节点根据公式推算出该节点左右孩子,父节点位置

 

4号节点:

父节点为4/2=2   i/2

左孩子节点:2*4 = 8  2*i

右孩子节点:2*4 + 1 = 9  2*i +1

2.上述完全二叉树存储在数组中

 

 

 定义一个Entry类,分别一个parent引用,left引用,right引用,并使用它们维护当前节点和别的节点之间的关系。

堆:完全二叉树+数组

 2.堆分大根堆和小根堆。

大根堆的要求是父节点比子节点的值大,

小根堆要求父节点的值比子节点的值小

什么是优先级队列呢?

1、是一个用队列存储的堆,对外接口从队头取元素,从队尾添加元素,再无其他取元素的方式

2、优先级队列内部元素是自动依照元素的权值排列。

PriorityQueue总是先输出根节点的值,然后调整树使之继续成为一棵完全二叉树 样每次输出的根节点总是整棵树优先级最高的,要么数值最小要么数值最大。

如何有序排列?

此题不能使用大顶堆,

定义一个大小为k的大顶堆,在每次移动更新大顶堆的时候,每次弹出都把最大的元素弹出去了,不能保留下来前K个高频元素。

此题用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。

代码:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] result = new int[k];
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int num : nums){
            map.put(num, map.getOrDefault(num, 0) + 1);
            // map.put,将指定key-value添加到(或修改)当前map对象中
            //map.getOrDefault,当map集合中有这个num时,就使用这个num对应的值;如果没有就使用0。
        }
        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
        //Set entrySet():返回所有key-value对构成的Set集合
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
        for (Map.Entry<Integer, Integer> entry : entries) {
            queue.offer(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }
         // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
        // for (int i = k - 1; i >= 0; i--) {
        //     result[i] = queue.poll().getKey();
        // }
        // return result;
        for (int i = 0; i < k; i++) {
            result[i] = queue.poll().getKey();
        }
        return result;
    }
}

 

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        HashMap<Integer,Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        PriorityQueue<Map.Entry<Integer, Integer>> que = new PriorityQueue<>((o1, o2) -> Integer.compare(o1.getValue(), o2.getValue()));
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            que.offer(entry);
            if (que.size() > k)
                que.poll();
        }
        for (int i = 0; i < k; i++)
            res[i] = que.poll().getKey();
        return res;
    }
}

 

 

BM47 寻找第k大

 用小顶堆,顶是最小的,保持堆中k个元素,顶就是第k个大的元素

import java.util.*;

public class Solution {
    public int findKth(int[] a, int n, int K) {
        ArrayList<Integer> r = new ArrayList<>();
        PriorityQueue<Integer> q = new PriorityQueue<>((o1, o2) -> o1.compareTo(o2));
        for (int i = 0; i < K; i++)
            q.offer(a[i]);
        for (int i = K; i < n; i++) {
            if (q.peek() < a[i]) {
                q.poll();
                q.offer(a[i]);
            }
        }return q.poll();
    }
}

 

 

BM46 最小的k个数

 用大顶堆,数字是从大到小,顶是最大的数,

只要保持堆中k个元素从大到小,每进来一个数比顶大的全不要,比顶小的全要并把顶踢出去。

顶已经是最大的了,最大的比新进元素还小,那剩下的数就更小了

import java.util.*;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> res = new ArrayList<>();
        if (input.length == 0 || k == 0)
            return res;
        PriorityQueue<Integer> q = new PriorityQueue<>((o1, o2) -> o2.compareTo(o1));
        for (int i = 0; i < k; i++) {
            q.offer(input[i]);
        }
        for (int i = k; i < input.length; i++) {
            if (q.peek() > input[i]) {
                q.poll();
                q.offer(input[i]);
            }
        }
        for (int i = 0; i < k; i++) {
            res.add(q.poll());
        }
        return res;
    }
}

 

posted @ 2021-11-04 22:15  最近饭吃的很多  阅读(97)  评论(0)    收藏  举报