【JAVA算法|hot100】堆类型题目详解笔记

这里记录刷hot100的思考过程详解,方便后续记忆复习。

题号215

215. 数组中的第K个最大元素

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

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

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

具体题解
java 复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        List<Integer> numList=new ArrayList<>();
        for(int num:nums){
            numList.add(num);
        }
        return quickselect(numList,k);
    } 
    public int quickselect(List<Integer> numList,int k){
        Random rand=new Random();
        int pivot=numList.get(rand.nextInt(numList.size()));

        List<Integer> small=new ArrayList<>();
        List<Integer> big=new ArrayList<>();
        List<Integer> equal=new ArrayList<>();
        for(int num:numList){
            if(num>pivot){
                big.add(num);
            }else if(num<pivot){
                small.add(num);
            }else{
                equal.add(num);
            }
        }

        if(k<=big.size()){
            return quickselect(big,k);
        }
        if(big.size()+equal.size()<k){
            return quickselect(small,k-big.size()-equal.size());
        }
        return pivot;
    }
}
思路解析

找第k大的元素,基于三路分区快速选择算法解决。找第K大元素即为找从小到大排序后的第K个元素,在这里先找一个基准值把元素划分为big,equal,small三组,然后判断要找的元素在哪一组,不断递归。

必会知识

1.通过随机选取基准值来提高算法时间复杂度的稳定性。

java 复制代码
Random random=new Random();
int pivot=numList.get(random.nextInt(numList.size()));

题号347

347. 前 K 个高频元素

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

具体题解
java 复制代码
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> hashmap =new HashMap<>();
        for(int num:nums){
            hashmap.put(num,hashmap.getOrDefault(num,0)+1);
        }
        Queue<int []> queue=new PriorityQueue<>(new Comparator<int []>(){
            @Override
            public int compare(int[] m,int[] n){
                return m[1]-n[1];
            }
        });
        for(Map.Entry<Integer,Integer> entry:hashmap.entrySet()){
            int num=entry.getKey(),count=entry.getValue();
            if(queue.size()==k){
                if(queue.peek()[1]<count){
                    queue.poll();
                    queue.offer(new int[]{num,count});
                }
            }else{
                queue.offer(new int[]{num,count});
            }
        }
        int[] ans=new int[k];
        for(int i=0;i<k;i++){
            ans[i]=queue.poll()[0];
        }
        return ans;
    }
}
思路解析

通过hashmap存储元素与出现次数的关系,然后实现基于出现次数排序的最小堆。对hashmap进行遍历,在堆中只存储出现次数最多的k个。这里细节较多。

必会知识

1.通过getOrDefault存储出现次数

2.通过Comparator实现最大堆

java 复制代码
Queue<int []> queue=new priorityQueue<>(new Comparator<>(){

    @Override
    public int compare(int[] x,int[] y){

        return x[1]-y[1];
    }

});

3.遍历hashmap

java 复制代码
for(Map.Entry<Integer,Integer> entry:hashmap.entrySet()){
    int num=entry.getKey(),count=entry.getValue;
}

题号295

295. 数据流的中位数

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。

  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

具体题解
java 复制代码
class MedianFinder {
    Queue<Integer> maxQueue;
    Queue<Integer> minQueue;
    public MedianFinder() {
        maxQueue=new PriorityQueue<>((x,y)->(y-x));
        minQueue=new PriorityQueue<>();
    }
    
    public void addNum(int num) {
        if(maxQueue.size()!=minQueue.size()){
            maxQueue.offer(num);
            minQueue.offer(maxQueue.poll());
        }else{
            minQueue.offer(num);
            maxQueue.offer(minQueue.poll());
        }
    }
    
    public double findMedian() {
        return maxQueue.size()!=minQueue.size()?maxQueue.peek()
        :(maxQueue.peek()+minQueue.peek())/2.0;
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
思路解析

用最大堆存储数据的前一半,最小堆存储数据的后一半,最终只会使用到两个堆的堆顶数据。最奥妙的部分是,利用最大堆or最小堆内部排序算法对新来数据排序。最终实现如果想添加数到最大(小)堆,那么先添加到最小(大)堆

必会知识

自定义最大堆

相关推荐
Drifter_yh2 小时前
「JVM」Java 垃圾回收机制全解析:回收算法、分代流转与 G1 收集器底层拆解
java·jvm·算法
天一生水water2 小时前
LangChain的智能体教程
开发语言·人工智能·langchain·php·智慧油田
啊哈哈哈哈哈啊哈哈2 小时前
Spring MVC 项目结构学习笔记
java·spring boot·spring·servlet·maven
adore.9682 小时前
2.21 oj基础89 90 91+U12B部分
开发语言·c++
yyjtx2 小时前
DHU上机打卡D28
开发语言·c++·算法
莫寒清2 小时前
Spring MVC:MultipartFile 详解
java·spring·mvc
johnny2332 小时前
《Vibe Coding:AI编程时代的认知重构》笔记
笔记·ai编程
JavaLearnerZGQ2 小时前
Spring SseEmitter 全面解析与使用示例
java·后端·spring
专注VB编程开发20年2 小时前
C#,VB.NET如何用GPU进行大量计算,提高效率?
开发语言·c#·.net