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

必会知识

自定义最大堆

相关推荐
StevenLdh13 分钟前
第四期 · 云端同步与冲突仲裁:离线可写、多端一致的工程解法
java·微信小程序
事已至此先睡覺吧23 分钟前
第三篇:Java 流程控制详解:条件判断、循环与跳转语句
java·开发语言
毕业设计70324 分钟前
(免费领源码) SpringBoot 游戏交易平台17600-java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
java·spring boot·mysql·决策树·mybatis·idea·推荐算法
一 乐31 分钟前
自习室座位预约管理系统|基于springboot + vue自习室座位预约管理系统(源码+数据库+文档)
java·vue.js·spring boot
m0_7345717632 分钟前
深入理解5g <二十> dmrs
开发语言·5g
此时不提桶,更待何时1 小时前
02-02-B-AQS与JUC锁面试与生产事故实战
java
小李不想当小白1 小时前
PCB结构与组成(PCB设计入门学习笔记)
经验分享·笔记·单片机·嵌入式硬件·学习·pcb工艺·pcb
音符犹如代码1 小时前
Kafka 接入 AI 的三条路线:MCP 提案、会话记忆与实时上下文
java·大数据·ai·kafka
vx_BS813301 小时前
【项目编号:project51629】Spring Boot 乡村自来水缴费系统:把抄表、水费生成与在线缴费做成一条数字化闭环
java·spring boot·eclipse·tomcat·maven
金金计较.1 小时前
Go语言-4
开发语言·golang