【算法练习Day11】滑动窗口最大值前 K 个高频元素

news2024/10/7 6:38:40

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 滑动窗口最大值
  • 前 K 个高频元素
  • 总结

滑动窗口最大值

239. 滑动窗口最大值 - 力扣(LeetCode)

这道题是一道困难题,给出一个滑动窗口的长度,给出一个数组,每次滑动窗口向数组右侧滑动一个元素,要求返回一个数组该数组记录的是每次移动滑动窗口所包含的数字中最大的一个分别是什么。
不难想出暴力解法,每移动一次遍历一遍窗口记录下来当前最大的数,时间复杂度是n*k,一共n个数据,要遍历k次。那么有没有更好的方法来节省时间呢?这时我们的单调队列要登场了!

什么是单调队列?

单调队列是单调递增的队列或者单调递减的队列,但是它和优先级队列的不同之处在于,我们设计它的时候主要是要维护大值或者小值而单调递增或递减的排序是进出元素控制的并非主要思路是排序,这和优先级队列的区别还是很大的,顺便说一下单调队列通常使用双端队列做模板实现,而优先级队列底层实现是堆,也就是二叉树。
本题我们可以借助双端队列创建一个单调队列,因为c++里没有现成的单调队列,单调队列只需要三个函数,一个push一个pop一个求最大值

我们如何每次都弹出最大值呢?

其实只是需要我们将最大值调整到队列口处,而前面小的数直接pop走,其实我们要求的是每次窗口中的最大值,所以小数完全没有必要维护,直接判断弹出即可,push时我们判断队尾有没有数小于要push进来的数,如果有全部pop出来,因为是在队尾插入所以要对对尾元素做判断,在实现pop函数时判断本次要删除的元素队头有没有,没有就不删(没有的原因是之前push元素时候已经弹出了,因为为了保证取最大值的函数每次都取最大)一开始直接push前k个元素,之后采取push一个元素pop一个元素的规律,值得注意的,不是每一次都要pop,但是每一次都要调用,至于具体这一步是否真的pop了在pop函数会自动判断。

为什么会这样呢?

原因在于我们设计的单调函数里实现的时候我们需要照顾到弹出最大值这个函数,所以我们设计成这样用来方便最大值的弹出,而在真正函数调用时候,为了保证逻辑上的正确,我们每次都要调用pop这个函数,判断如果此时我们要删的元素不在队头部,那么直接往后走加入新元素即可。

class Solution {
private:
    class MyQueue 
    { //单调队列(从大到小)
    public:
        deque<int> que; // 使用deque来实现单调队列
        // 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
        // 同时pop之前判断队列当前是否为空。
        void pop(int value) 
        {
            if (!que.empty() && value == que.front()) 
            {
                que.pop_front();
            }
        }
        // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
        // 这样就保持了队列里的数值是单调从大到小的了。
        void push(int value) {
            while (!que.empty() && value > que.back()) 
            {
                que.pop_back();
            }
            que.push_back(value);
        }
        // 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
        int front() 
        {
            return que.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        for (int i = 0; i < k; i++) 
        { // 先将前k的元素放进队列
            que.push(nums[i]);
        }
        result.push_back(que.front()); // result 记录前k的元素的最大值
        for (int i = k; i < nums.size(); i++) 
        {
            que.pop(nums[i - k]); // 滑动窗口移除最前面元素
            que.push(nums[i]); // 滑动窗口前加入最后面的元素
            result.push_back(que.front()); // 记录对应的最大值
        }
        return result;
    }
};

时间复杂度: O(n)
空间复杂度: O(k)

前 K 个高频元素

347. 前 K 个高频元素 - 力扣(LeetCode)
这道题是考察优先级队列和语法理解

这道题是一个输出前k个高频元素的题,并不是只输出一个。所以我们想到用优先级队列来存取前k个高频元素

那么如何判断哪些是高频元素呢?

我们用unordered_map来存取每个数据出现的次数,然后用小顶堆来存取数据。

为什么要用小顶堆而不是大顶堆?

我们的思路是定义一个只能存k个元素的堆,这样我们只需要维护k个数据,减少不必要的浪费。由于哈希存储结果是unordered_map来提高效率,所以map里是无序的,我们在插入元素时候要按着map依次插入进去,而用大顶堆的话,大的数据排在前面如果map里还有更大的数据,那么之前最大的数据要先被弹出来,往复操作最后只剩下频率最低的k个元素。而使用小顶堆那么每次弹出最小元素,加进来较大元素,最后沉淀下来的是k个高频数据。当然如果使用的是map的话可能就不需要考虑这些问题,因为是排好序的。

按着刚才的思路写出代码

class Solution {
public:
    // 小顶堆
    class mycomparison 
    {
    public:
        bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) 
        {
            return lhs.second > rhs.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) 
    {
        // 要统计元素出现频率
        unordered_map<int, int> map; // map<nums[i],对应出现的次数>
        for (int i = 0; i < nums.size(); i++) 
        {
            map[nums[i]]++;
        }

        // 对频率排序
        // 定义一个小顶堆,大小为k
        priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;

        // 用固定大小为k的小顶堆,扫面所有频率的数值
        for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) 
        {
            pri_que.push(*it);
            if (pri_que.size() > k) 
            { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
                pri_que.pop();
            }
        }

        // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) 
        {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

注意:把map的两个数据都放到堆里,然后根据二元组的第二个关键词来进行排序,这样我们在进行最后一步转化为数组的时候,才能根据频率找到对应的数据,缺一不可

总结

今天我们完成了滑动窗口最大值、前 K 个高频元素两道题目,相关的思想需要多复习回顾。接下来,我们继续进行算法练习·。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

stm32之HAL库操作PAJ75620

一、模块简介 手势模块PAJ7620主要利用IIC或SPI协议来实现数据的传输&#xff0c;本实验用的模块是以IIC来进行信息传输。支持电压从2.8v到3.6v, 正常可以选择3.3v。检测的距离从5到15cm, 可以检测9种手势&#xff0c;包括 右&#xff1a;编码为 0x01左&#xff1a;编码为 0x0…

FDM3D打印系列——黄金弗利萨

大家好&#xff0c;我是阿赵。   国庆期间&#xff0c;在家打印了一个黄金弗利萨的3D模型&#xff0c;和大家分享一下。模型在创想云上面下载的。 使用的设备依然是创想三维的Sermoon V1 Pro&#xff0c;使用的打印材料是创想三维的PLA高速打印素材。 不得不说&#xff0c;…

经典场的量子化

专栏目录: 高质量文章导航-持续更新中-CSDN博客 前置:复指数引起的思考 往指数函数e上丢一个复矢量出来的也是一个复矢量 其定义参考之前的文章群论-李代数_GZVIMMY的博客-CSDN博客 进一步了解下复矢量空间 首先了解下复球面(用一个球表示了所有的复数) 形如[x,y]的二维实…

科普rabbitmq,rocketmq,kafka三者的架构比较

对比 架构对比 从架构可以看出三者有些类似&#xff0c;但是在细节上有很多不同。下面我们就从它们的各个组件&#xff0c;介绍它们&#xff1a; RabbitMQ&#xff0c;是一种开源的消息队列中间件。下面是RabbitMQ中与其相关的几个概念&#xff1a; 1.生产者&#xff08;P…

微软输入法如何打勾和箭头的符号

文章目录 一、打 “√” 符号二、打 “←” 和 “→” 符号 一、打 “√” 符号 选中 “表情包” 图标 选中 “Ω” 符号后&#xff0c;下拉找到 “√” 即可。 微软输入法打 “ ”这个符号直接输入拼音“cha”就行。 二、打 “←” 和 “→” 符号 拼音直接打 “zuo” 或 “…

GET 和 POST的区别

GET 和 POST 是 HTTP 请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过 WEB 开发的人都能说出一二。 最直观的区别就是 GET 把参数包含在 URL 中&#xff0c;POST 通过 request body 传递参数。 你可能自己写过无数个 GET 和 POST 请求&#xff0c;或者已经看…

扫雷小游戏(简单详细)(内附完整代码)

设计总体思路 实现游戏可以一直玩&#xff0c;先打印棋盘&#xff0c;玩家和电脑下棋&#xff0c;最后分出胜负。 如果编写较大的程序&#xff0c;我们可以分不同模块 例如这个扫雷&#xff0c;我们可以创建三个文件 分别为&#xff1a; game.h 函数的声明game.c 函数的…

《深度不确定条件下的决策:从理论到实践》PDF

制定未来计划时需要预测变化&#xff0c;尤其是制定长期计划或针对罕见事件的计划时。当这些变化存在高度不确定性的时候&#xff0c;这种预期就变得越来越困难。 今天给大家介绍的这本《深度不确定条件下的决策&#xff1a;从理论到实践》正是解决以上问题的良方。完整书籍文…

注意力机制是否比矩阵分解更好?——IS ATTENTION BETTER THAN MATRIX DECOMPOSITION?

原文链接&#xff1a;https://openreview.net/pdf?id1FvkSpWosOlhttps://openreview.net/pdf?id1FvkSpWosOl 代码库&#xff1a;​​​​​​​​​​​​​​GitHub - Gsunshine/Enjoy-Hamburger: [ICLR 2021 top 3%] Is Attention Better Than Matrix Decomposition?[ICL…

苹果ios系统IPA包企业签名手机下载应用可以有几种方式可以下载到手机?

一、App Store签名&#xff1a;这是最常见和推荐的苹果签名方式。用户可以通过苹果的官方应用商店App Store下载并安装经过苹果审核的应用程序。这种签名方式确保了应用程序的安全性和可靠性&#xff0c;因为App Store对应用进行了严格的审核和验证。 二、企业签名&#xff1a;…

三、互联网技术——IP子网划分

文章目录 一、IP地址基础1.1 IP地址分类1.2 网络掩码/子网掩码 二、子网划分VLSM2.1 为什么要进行子网划分2.2 怎么进行子网划分2.3 子网划分原理2.4 例题一2.5 例题二2.6 例题三2.6 例题四2.7 例题五2.8 例题六2.9 例题七2.10 例题八 三、无类域间路由CIDR3.1 例题一3.2 例题二…

基于Android的英语学习软件/英语学习系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的APP应运而生&#xff0c;各行各业相继进入信息管理时代&#x…

扩散模型diffusion model 代码解读

代码来自这里 使用pytorch轻松实现简单扩散模型diffusion model&#xff08;附可跑通全部代码&#xff09; - 知乎 1.作者首先自己定义了一个数据集&#xff0c;也就是一堆散点&#xff0c;组成的S。 2.这些都是预先设置好的参数&#xff0c;也就是利用这些来做learning的提示…

国庆10.04

服务器 代码 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器头文件 #include<QTcpSocket> //客户端头文件 #include<QList> //链表容器 #include<QMessag…

数据结构与算法--算法

这里写目录标题 线性表顺序表链表插入删除算法 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 一级目录二级目录二级目录二级目录 线性表 顺序表 链表 插入删除算法 步骤 1.通过循环到达指定位置的前一个位置 2.新建…

知网G4《基础教育论坛》期刊投稿邮箱

知网G4《基础教育论坛》期刊投稿邮箱 《基础教育论坛》文稿要求5000字符3版&#xff0c;查重率15%以下。 所有投稿必须在文后注明&#xff1a;作者姓名、性别、出生年&#xff08;如1968—&#xff09;、工作单位、通讯地址&#xff08;注明所在地及邮编&#xff09;。 对于科…

postgresql-物化视图

postgresql-物化视图 物化视图创建物化视图刷新物化视图修改物化视图删除物化视图 物化视图 创建物化视图 postgresql使用create materialized view 语句创建视图 create materialized view if not exists name as query [with [NO] data];-- 创建一个包含员工统计信息的物化…

Flink--8、时间语义、水位线(事件和窗口、水位线和窗口的工作原理、生产水位线、水位线的传递、迟到数据的处理)

星光下的赶路人star的个人主页 将自己生命力展开的人&#xff0c;他的存在&#xff0c;对别人就是愈疗 文章目录 1、时间语义1.1 Flink中的时间语义1.2 哪种时间语义更重要 2、水位线&#xff08;Watermark&#xff09;2.1 事件时间和窗口2.2 什么是水位线1.3 水位线和窗口的工…

竞赛 大数据商城人流数据分析与可视化 - python 大数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的基站数据分析与可视化 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度…