算法打卡day11|栈与队列篇03|Leetcode 239. 滑动窗口最大值、347.前 K 个高频元素

news2024/11/18 15:39:06

小顶堆和大顶堆

小顶堆(Min Heap)和大顶堆(Max Heap)是两种特殊的完全二叉树,它们遵循特定的堆属性,即父节点的值总是小于或等于(小顶堆)或者大于或等于(大顶堆)其子节点的值。这种结构使得堆的根节点包含了最大值或者最小值,这使得堆在很多算法中非常有用,尤其是在优先级队列的实现上。

小顶堆(Min Heap)
在小顶堆中,每个非叶子节点的值都必须大于或等于其子节点的值。这意味着堆的根节点包含了所有节点中的最小值。小顶堆通常用于那些需要快速访问最小元素的场景比如实现优先队列也就是今天的力扣347题

大顶堆(Max Heap)
在大顶堆中,每个非叶子节点的值都必须小于或等于其子节点的值。因此,堆的根节点包含了所有节点中的最大值。大顶堆通常用于需要快速访问最大元素的场景

堆的操作
堆提供了几种基本操作:

  • insert(或add):向堆中添加一个新元素。
  • remove:移除堆中的最大元素(在大顶堆中)或最小元素(在小顶堆中)。
  • heapify:将一个数组转换成堆结构。
  • extractMax / extractMin:从堆中提取并移除最大元素(在大顶堆中)或最小元素(在小顶堆中)。

在Java中实现堆,Java标准库中的PriorityQueue就是基于堆实现的,默认情况下它使用小顶堆。可以指定一个Comparator来改变优先级队列的比较规则,从而可以实现大顶堆。

算法题

Leetcode  239. 滑动窗口最大值

题目链接:239. 滑动窗口最大值

大佬视频讲解:滑动窗口最大值视频讲解

个人思路

思路打结,不知道怎么实现

解法
单调队列

使用单调递减队列,将放进去窗口里的元素随着窗口的移动,队列也一进一出,每次移动之后,队列直接知道最大值是什么。

还有注意,队列没有必要维护窗口里的所有元素只需要维护有可能成为窗口里最大值的元素,同时保证队列里的元素数值是由大到小的。

设计单调队列的时候,pop,和push操作要保持如下规则:

  1. poll(val):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  2. add(val):如果add的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到add元素的数值小于等于队列入口元素的数值为止

保持如上规则,每次窗口移动的时候,只要deque.peek()就可以返回当前窗口的最大值。

class MyQueue {
    Deque<Integer> deque = new LinkedList<>();
    //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出;
   
    void poll(int val) {
        if (!deque.isEmpty() && val == deque.peek()) { //也要判断队列当前是否为空
            deque.poll();
        }
    }
    //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出,这样保证队列元素单调递减
    //比如此时队列元素4,3,1 ;5将要入队,比4,3,1都大,所以都弹出,此时队列:5
    void add(int val) {
        while (!deque.isEmpty() && val > deque.getLast()) {
        //push元素的数值小于等于队列入口元素的数值为止
            deque.removeLast();
        }
        deque.add(val);
    }
    
    //队列队顶元素始终为最大值
    int peek() {
        return deque.peek();
    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums.length == 1) {
            return nums;
        }
        int len = nums.length - k + 1;
        int[] res = new int[len];//存放结果元素的数组
        int num = 0;
        
        MyQueue myQueue = new MyQueue();//自定义队列

        //先将前k的元素放入队列
        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        res[num++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {
            myQueue.poll(nums[i - k]); //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列
            
            myQueue.add(nums[i]);//滑动窗口加入最后面的元素
        
            res[num++] = myQueue.peek();//记录对应的最大值
        }
        return res;
    }
}

时间复杂度:O(n);(遍历数组)

空间复杂度:O(n);(辅助数组和队列)

Leetcode 347.前 K 个高频元素

题目链接:347.前 K 个高频元素

大佬视频讲解:前 K 个高频元素 视频讲解

个人思路

根据题意解答分为三步走,第一步要统计元素出现频率,第二步对频率排序,第三步找出前K个高频元素

解法
小顶堆

第一步统计元素出现的频率,这一类的问题可以使用map来进行统计。

第二步对频率进行排序,可以使用一种 容器适配器就是优先级队列,就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。

第三步找出前k个高频元素因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。

如下图所示

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数

        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }

        //在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
        //出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(小顶堆)
        PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);

        for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序
           
             if(pq.size()<k){//小顶堆元素个数小于k个时直接加
                pq.add(new int[]{entry.getKey(),entry.getValue()});
            }else{
                if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点

             //弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了
                    pq.poll();

                    pq.add(new int[]{entry.getKey(),entry.getValue()});
                }
            }
        }

        int[] ans = new int[k];//结果数组
        for(int i=k-1;i>=0;i--){//依次弹出小顶堆;先弹出的是堆的根,出现次数少,后面弹出的出现次数多
            ans[i] = pq.poll()[0];
        }
        return ans;
    }
}

时间复杂度:O(nlogk);(小顶堆构建)

空间复杂度:O(n);(优先队列,结果数组都不超过n)

以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网代码随想录算法官网代码随想录算法官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序开发系列(二十二)·wxml语法·双向数据绑定model:的用法

目录 1. 单向数据绑定 2. 双向数据绑定 3. 代码 在 WXML 中&#xff0c;普通属性的绑定是单向的&#xff0c;例如&#xff1a;<input value"((value))"/> 如果希望用户输入数据的同时改变 data 中的数据&#xff0c;可以借助简易双向绑定机制。在对应属性…

文心一言 VS 讯飞星火 VS chatgpt (210)-- 算法导论16.1 1题

一、根据递归式(16.2)为活动选择问题设计一个动态规划算法。算法应该按前文定义计算最大兼容活动集的大小 c[i,j]并生成最大集本身。假定输入的活动已按公式(16.1)排好序。比较你的算法和GREEDY-ACTIVITY-SELECTOR的运行时间。如何要写代码&#xff0c;请用go语言。 文心一言&…

阿里云和腾讯云区别价格表,云服务器费用对比2024年最新

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器61元一年&#xff0c;2核2G3M、2核4G、4核8G、4核16G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配…

利用tree命令自动保存文件层级结构

tree命令的使用 为了将上图左侧的文件目录&#xff0c;生成上图右侧中的文件夹结构列表&#xff0c;保存在txt中&#xff0c;使用了如下cmd命令&#xff1a; C:\armadillo-12.8.0>tree .>list.txt以上tree命令分为3部分&#xff1a; tree 命令. 在当前目录>list.tx…

ChatGPT:人工智能的革命与未来

引言 随着人工智能技术的飞速发展&#xff0c;ChatGPT作为OpenAI推出的一款语言模型&#xff0c;已经引起了广泛的关注和讨论。它不仅改变了我们与机器交流的方式&#xff0c;还为众多行业的发展带来了革命性的影响。本文将深入探讨ChatGPT的技术原理、应用场景以及它对未来的…

一些硬件知识(六)

防反接设计&#xff1a; 同步电路和异步电路的区别: 同步电路:存储电路中所有触发器的时钟输入端都接同一个时钟脉冲源&#xff0c;因而所有触发器的状态的变化都与所加的时钟脉冲信号同步。 异步电路:电路没有统一的时钟&#xff0c;有些触发器的时钟输入端与时钟脉冲源相连…

【HarmonyOS】ArkTS-箭头函数

箭头函数 箭头函数是 比普通函数 更简洁 的一种函数写法 () > {}() > {// 函数体 }let 函数名 () > {// 函数体 }let 函数名 () > {// 函数体 } 函数名(实参1, 实参2)let 函数名 (形参1: 类型, 形参2: 类型) > {// 函数体 } 函数名(实参1, 实参2)let 函数名 …

【嵌入式】嵌入式系统稳定性建设:静态代码扫描的稳定性提升术

1. 概述 在嵌入式系统开发过程中&#xff0c;代码的稳定性和可靠性至关重要。静态代码扫描工具作为一种自动化的代码质量检查手段&#xff0c;能够帮助开发者在编译前发现潜在的缺陷和错误&#xff0c;从而增强系统的稳定性。本文将介绍如何在嵌入式C/C开发中使用静态代码扫描…

嵌入式学习第二十五天!(网络的概念、UDP编程)

网络&#xff1a; 可以用来&#xff1a;数据传输、数据共享 1. 网络协议模型&#xff1a; 1. OSI协议模型&#xff1a; 应用层实际收发的数据表示层发送的数据是否加密会话层是否建立会话连接传输层数据传输的方式&#xff08;数据包&#xff0c;流式&#xff09;网络层数据的…

Day22:安全开发-PHP应用留言板功能超全局变量数据库操作第三方插件引用

目录 开发环境 数据导入-mysql架构&库表列 数据库操作-mysqli函数&增删改查 数据接收输出-html混编&超全局变量 第三方插件引用-js传参&函数对象调用 完整源码 思维导图 PHP知识点&#xff1a; 功能&#xff1a;新闻列表&#xff0c;会员中心&#xff0…

Python爬虫——scrapy-3

目录 免责声明 任务 文件简介 爬取当当网内容单管道 pipelines.py items.py setting dang.py 当当网多管道下载图片 pipelines.py settings 当当网多页下载 dang.py pielines.py settings items.py 总结 免责声明 该文章用于学习&#xff0c;无任何商业用途 …

深度学习-2.3损失函数

文章目录 损失函数深度学习优化思想回归&#xff1a;误差平方和SSE二分类交叉熵损失函数1. 极大似然函数估计求解二分类交叉熵函数2.用tensor实现二分类交叉熵损失 多分类交叉熵损失函数1.由二分类推广到多分类2.用PyTorch实现多分类交叉熵损失 损失函数 在之前的文章中&#…

OpenAI劲敌吹新风! Claude 3正式发布,Claude3使用指南

Claude 3是什么&#xff1f; 是Anthropic 实验室近期推出的 Claude 3 大规模语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;系列&#xff0c;代表了人工智能技术的一个显著飞跃。 该系列包括三个不同定位的子模型&#xff1a;Claude 3 Haiku、Claude 3…

Chapter20-Ideal gases-CIE课本要点摘录、总结(编辑中)

20.1 Particles of a gas Brownian motion Fast modules 速率的数值大概了解下&#xff1a; average speed of the molecules:400m/s speed of sound:approximately 330m/s at STP&#xff08;standard temperature and pressure&#xff09; Standard Temperature and Pres…

如何使用WinSCP结合Cpolar实现公网远程访问内网Linux服务器

文章目录 1. 简介2. 软件下载安装&#xff1a;3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 ​ Winscp是一个支持SSH(Secure SHell)的可视化SCP(Secure Copy)文件传输软件&#xff0c;它的主要功能是在本地与远程计…

linux上安装fastdfs及配置

一、基础环境准备 1、所需软件 名称说明libfastcommonfastdfs分离出的一些公用函数包fastdfsfastdas软件包fastdfs-nginx-modulefastdfst和nginx的关联模块nginxnginxl软件包 2、编辑环境 安装一些基础的支持环境 yum install git gccc gcc-c make automake autoconf libto…

图遍历算法

图的遍历算法有两种&#xff1a;深度优先遍历、广度优先遍历算法。 深度优先遍历算法就是从起始结点开始&#xff0c;只要有相邻且未被访问的结点就要直接进行访问&#xff0c;直到最后不能向下遍历为止&#xff0c;再回溯寻找下一个策略。 广度优先遍历算法&#xff0c;就是从…

线性代数笔记13--正交向量和正交子空间

0. 四个子空间 1. 正交向量 两向量点乘为0&#xff0c;向量正交。 A ⊤ B 0 A^{\top}B0 A⊤B0 勾股定理 ∣ ∣ x ∣ ∣ 2 ∣ ∣ y 2 ∣ ∣ ∣ ∣ x y ∣ ∣ 2 ||x||^2||y^2||||xy||^2 ∣∣x∣∣2∣∣y2∣∣∣∣xy∣∣2 验证正交条件 ∣ ∣ x ∣ ∣ 2 x ⊤ x x x ⊤ ∣…

vue2【详解】生命周期(含父子组件的生命周期顺序)

1——beforeCreate&#xff1a;在内存中创建出vue实例&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置还没调用&#xff08;data 和 methods 属性还没初始化&#xff09; 【执行数据观测 (data observer) 和 event/watcher 事件配置】 2——created&#xf…

前TVB「御用泼妇」原来是亿万富婆,离婚后狂买楼养大子女。

今年72岁的昔日TVB老戏骨陈曼娜Manna姐最近突然亮相隔壁ViuTV的新剧《飞黄腾达》&#xff0c;本色出演炒股女富豪&#xff0c;她大赞剧集监制、导演有眼光&#xff0c;角色的背景与她本身十分相似&#xff0c;演起来可谓得心应手。 众所周知&#xff0c;陈曼娜最爱「买砖头」&a…