【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最小堆内部排序算法对新来数据排序。最终实现如果想添加数到最大(小)堆,那么先添加到最小(大)堆

必会知识

自定义最大堆

相关推荐
码上解惑4 分钟前
从 Dify 工作流说起:常用节点怎么选、怎样组合?
java·人工智能·ai·agent·dify·智能体·spring ai
殷忆枫12 分钟前
AI笔记三十七:AI边缘端道桥安全监测系统:YOLOv8n推理与Web监控全解析
笔记·yolo
小大宇32 分钟前
python flask框架 SSE流式返回、跨域、报错
开发语言·python·flask
逸模1 小时前
轻加盟模式,稳住品牌统一调性的思路
笔记·建模·公装·翻模·交底
青山木1 小时前
Hot 100 --- 岛屿数量
java·数据结构·算法·leetcode·深度优先·广度优先
柒星栈1 小时前
PHP 源码怎么加密防破解?三套方案实战指南
开发语言·php·android studio
勉灬之1 小时前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
程序员-珍1 小时前
报错下载android sdk失败
android·java
糖果店的幽灵1 小时前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
whyTeaFo1 小时前
GAMES101: Lecture 10: Geometry 1 (Introduction) ppt笔记
笔记