代码随想录算法训练营第十二天 | 239. 滑动窗口最大值,347.前 K 个高频元素 [栈与队列篇]

代码随想录算法训练营第十二天

  • LeetCode 239. 滑动窗口最大值
    • 题目描述
    • 思路
    • 参考代码
    • 总结
  • LeetCode 347.前 K 个高频元素
    • 题目描述
    • 思路
    • 参考代码

LeetCode 239. 滑动窗口最大值

题目链接:239. 滑动窗口最大值
文章讲解:代码随想录#239. 滑动窗口最大值
视频讲解:单调队列正式登场!| LeetCode:239. 滑动窗口最大值

题目描述

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例1

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

示例2

输入:nums = [1], k = 1
输出:[1]

提示

  • 1 <= nums.length <= 10^5
  • 10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

思路

这道题主要是考查队列结构。
对于初次接触的同学,可以先看一下卡哥的讲解视频,然后再结合代码随想录的思路好好推导一下。

以下是我结合卡哥的视频和随想录的思路整理出我对这道题的理解。
说到滑动窗口,想到了之前做的 209.长度最小的子数组 ,第一反应就是双指针,先对整个数组进行遍历,然后再挨个遍历滑动窗口中的k个数,求出最大值,这样肯定可以解决这道题,不过时间复杂度挺大的,为O(n*k)。
那么有没有时间复杂度较小的解决方案吗? 肯定有,那就需要在遍历整个数组时,再配合队列。

队列两端,一边是入口,一边是出口。数组的窗口每次移动时,从队列的出口处pop出要移除的元素,同时需要向队列的入口处push进要添加的元素,然后在队列中找到最大值。
因为要求窗口内的最值,所以我们需要使用到单调队列
那如何体现是单调队列呢?

  • 每次向队列中push要添加的元素时,需要与队列入口处的元素进行比较。如果要添加的元素大于入口处的元素,则将入口处的元素pop出队列,然后继续比较入口处的下一个元素,直到要添加的元素小于等于入口处的元素或者队列为空,才将该元素push到入口处。(这是关键,保证单调队列是递减的,可以找到最大值)
  • 每次从队列的出口处pop元素时,需要与队列出口处的元素进行比较,如果相等,则将该出口处的元素pop出队列,如果小于,则不需要做任何操作。(在push时,已经将小于的元素pop过了,当前队列中不存在这样的元素,也不存在任何大于的元素,因为在push时添加的就是窗口内最大的元素)

这样队列的出口处就保存了当前窗口中元素的最大值。
因为我们只遍历了一遍数组,所以时间复杂度为O(n)。

参考代码

// 仅供参考,代码没有完全通过
struct quenen {
    int val;
    struct quenen *next;
} Stack;

typedef struct quenen Quenen;

Quenen *quenenCreate() {
    Quenen *obj = (Quenen *)malloc(sizeof(Quenen));
    obj->next = NULL;
    return obj;
}

bool isQuenenEmpty(Quenen *obj)
{
    if (obj->next == NULL) {
        return true;
    }
    return false;
}

int getQuenenTail(Quenen *obj)
{
    Quenen *cur = obj;
    while (cur->next != NULL) {
        cur = cur->next;
    }
    return cur->val;
}

void QuenenPopTail(Quenen *obj)
{
    Quenen *cur = obj;
    while (cur->next != NULL && cur->next->next != NULL) {
        cur = cur->next;
    }

    Quenen *tmp = cur->next;
    cur->next = tmp->next;
    free(tmp);
}

void push(Quenen *obj, int val)
{
    Quenen *cur = obj;
    while (cur->next != NULL) {
        cur = cur->next;
    }

    Quenen *node = (Quenen *)malloc(sizeof(Quenen));
    node->next = NULL;
    node->val = val;
    cur->next = node;
}

int getQuenenHead(Quenen *obj)
{
    return obj->next->val;
}

void QuenenPopHead(Quenen *obj)
{
    Quenen *tmp = obj->next;
    obj->next = tmp->next;
    free(tmp);
}

void quenenPush(Quenen* obj, int x)
{
    while (!isQuenenEmpty(obj) && x > getQuenenTail(obj)) {
        QuenenPopTail(obj);
    }
    push(obj, x);
}

void quenenPop(Quenen* obj, int x)
{
    if (!isQuenenEmpty(obj) && x == getQuenenHead(obj)) {
        QuenenPopHead(obj);
    }
}

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize)
{
    int *ret = (int*)malloc(100000*sizeof(int));
    int cnt = 0;
    Quenen *obj = quenenCreate();

    for (int i = 0; i < k; i++) {
        quenenPush(obj, nums[i]);
    }
    ret[cnt++] = getQuenenHead(obj);

    for (int i = k; i < numsSize; i++) {
        quenenPop(obj, nums[i - k]);
        quenenPush(obj, nums[i]);
        ret[cnt++] = getQuenenHead(obj);
    }
    *returnSize = cnt;

    return ret;
}

总结

  1. 看这道题的思路,头一次见到了这些词:单调队列、大顶堆、小顶堆。而这道题用的就是单调队列,所谓的单调队列即队列中的元素是单调递增或单调递减的。
    比如,对于单调递减队列来说,队列中存在的元素都是递减,一旦向队列中push了一个比所有元素都要大的值,那需要从队列的入口处依次pop出较小的元素。
  2. 我这种写法竟然超时了,数据量一大,单链表操作效率就变得很低了。
    在这里插入图片描述
  3. 改成双链表实现队列,用例总算是通过了,但是效率不高。
    在这里插入图片描述
    参考代码如下
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
struct quenen {
    int val;
    struct quenen *next;
    struct quenen *pre;
} Stack;

typedef struct quenen Quenen;

Quenen *quenenCreate() {
    Quenen *obj = (Quenen *)malloc(sizeof(Quenen));
    obj->next = obj;
    obj->pre = obj;
    return obj;
}

bool isQuenenEmpty(Quenen *obj)
{
    if (obj->next == obj) {
        return true;
    }
    return false;
}

int getQuenenTail(Quenen *obj)
{
    return obj->pre->val;
}

void QuenenPopTail(Quenen *obj)
{
    Quenen *tmp = obj->pre;
    tmp->pre->next = obj;
    obj->pre = tmp->pre;
    free(tmp);
}

void push(Quenen *obj, int val)
{
    Quenen *node = (Quenen *)malloc(sizeof(Quenen));
    node->val = val;

    node->next = obj;
    node->pre = obj->pre;
    obj->pre->next = node;
    obj->pre = node;
}

int getQuenenHead(Quenen *obj)
{
    return obj->next->val;
}

void QuenenPopHead(Quenen *obj)
{
    Quenen *tmp = obj->next;
    obj->next = tmp->next;
    tmp->next->pre = obj;
    free(tmp);
}
  1. 看官方的答案写得挺短的,用了数组就实现了单调队列,后面有机会好好研究下。

LeetCode 347.前 K 个高频元素

题目链接:347.前 K 个高频元素
文章讲解:代码随想录#347.前 K 个高频元素
视频讲解:LeetCode:347.前 K 个高频元素

题目描述

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

示例1

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例2

输入: nums = [1], k = 1
输出: [1]

提示

  • 1 <= nums.length <= 10^5
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

思路

为啥C语言就没有那么多API,为啥都要自己去实现封装,问题是搞出来效率还低得不行,就像上道题。
看来只能等到后面搞完二叉树,这道题是不是就能搞定了。
如何用C语言实现小顶堆呢,这是个关键问题。

参考代码

以后有机会二刷吧

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

现货黄金突破2050美元 后续还会涨吗?

一两个月以前&#xff0c;受美联储降息预期影响&#xff0c;现货黄金价格一度强势上涨&#xff0c;并且刷新历史新高。随后&#xff0c;市场不断消化降息预期&#xff0c;金价逐步回落&#xff0c;盘中一度下探2000大关。在今年的一季度&#xff0c;行情再度发生变化&#xff0…

华为5G沸沸扬扬!那你知道三防平板网络是什么类型呢!

近日&#xff0c;华为在5G的事件在热搜上可是着实的火了一把啊&#xff01;让小编想起一款来自亿道信息EM-I22K-5G的一款三防平板产品&#xff0c;你知道是什么网络类型的呢&#xff1f; EM-I22K-5G 不知道&#xff1f;没关系呀&#xff01;小编可以为你普及亿道信息EM-I22K-5G…

寒假作业-day5

TCP和UDP区别 TCP ----稳定 1、提供面向连接的&#xff0c;可靠的数据传输服务&#xff1b; 2、传输过程中&#xff0c;数据无误、数据无丢失、数据无失序、数据无重复&#xff1b; 3、数据传输效率低&#xff0c;耗费资源多&#xff1b; 4、数据收发是不同步的&#xff1b; UD…

软件价值8-站点连通性检查

站点连通性检查&#xff0c;即看网站是否能访问得通&#xff0c;实用价值不大&#xff0c;不过用来作软件应用入门还不错。 代码&#xff1a; import urllib.request import tkinter as tkdef test_connectivity():window tk.Tk()window.geometry(600x400)window.resizable(F…

性能实测:分布式存储 ZBS 与集中式存储 HDS 在 Oracle 数据库场景表现如何

作者&#xff1a;深耕行业的 SmartX 金融团队 金鑫 在金融客户的基础架构环境中&#xff0c;HDS 是一种被广泛使用的存储解决方案。作为集中式存储的代表之一&#xff0c;HDS 拥有高性能、高可用性和可扩展性的企业级存储特点&#xff0c;适用于实时数据处理、虚拟化和灾难备份…

阿里云游戏服务器一年费用多少?

阿里云游戏服务器租用价格表&#xff1a;4核16G服务器26元1个月、146元半年&#xff0c;游戏专业服务器8核32G配置90元一个月、271元3个月&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价&#xff1a; 阿里云游戏服务器租用价格表 阿…

论文阅读-Transformer-based language models for software vulnerability detection

「分享了一批文献给你&#xff0c;请您通过浏览器打开 https://www.ivysci.com/web/share/biblios/D2xqz52xQJ4RKceFXAFaDU/ 您还可以一键导入到 ivySCI 文献管理软件阅读&#xff0c;并在论文中引用 」 本文主旨&#xff1a;本文提出了一个系统的框架来利用基于Transformer的语…

JavaScript常用技巧专题七

文章目录 一、提炼函数1.1、好处1.2、示例 二、合并重复的条件片段三、把条件分支语句提炼成函数四、合理使用循环五、提前让函数退出代替嵌套条件分支六、传递对象参数代替过长的参数列表七、少用三目运算符八、合理使用链式调用8.1、优点8.2、缺点 九、纯函数9.1、不属于纯函…

2-2 动手学深度学习v2-损失函数-笔记

损失函数&#xff0c;用来衡量预测值和真实值之间的区别。是机器学习里面一个非常重要的概念。 三个常用的损失函数 L2 loss、L1 loss、Huber’s Robust loss 均方损失 L2 Loss l ( y , y ′ ) 1 2 ( y − y ′ ) 2 l(y,y^{\prime})\frac{1}{2}(y-y^{\prime})^{2} l(y,y′)21…

火山引擎ByteHouse:如何为OLAP设计高性能向量检索能力?

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 背景 随着 LLM 技术应用及落地&#xff0c;数据库需要提高向量分析以及 AI 支持能力&#xff0c;向量数据库及向量检索等能力“异军突起”&#xff0c;迎来业界持续…

第七届西湖论剑·中国杭州网络安全技能大赛 AI 回声海螺 WP

第七届西湖论剑中国杭州网络安全技能大赛-AI-回声海螺 开题&#xff0c;提示输入密码给FLAG。 这个回声海螺应该是个AI&#xff0c;就是复读机&#xff0c;应该是想办法从中骗出密码。 感觉这题不像是AI&#xff0c;也没用啥模型&#xff0c;应该是WEB。或者是说类似于AI的提示…

第八讲:详解第1套真题

第八讲:详解第1套真题 基本编程题【15 分】简单应用题【25 分】综合应用题【20 分】**问题一**【5分】问题二【5 分】问题二【10 分】小结基本编程题【15 分】 考生文件夹下存在一个文件 PY101.py,请写代码替换横线,不修改其他代码,实现以下功能:【5 分】键盘输入正整数 n…

【从0上手Cornerstone3D】如何使用CornerstoneTools中的工具之同步器

同步器&#xff08;Synchronizers&#xff09;可以使多个视图同步响应同一个工具的操作&#xff0c;例如我们在MPR视图下&#xff0c;同步操作三个视图的缩放程度、windowLevel等等 一个同步器必须需要以下几个部分才可以执行 一个监听事件&#xff08;什么情况下触发同步&…

【日志记录】——单片机可执行文件合并

一&#xff1a;需求场景 现在有一片单片机&#xff0c;执行程序包括自定义boot和应用程序app, 在将打包好的固件给到生产时有以下问题&#xff0c;由于要通过jlink烧录boot&#xff0c;然后上电启动boot&#xff0c;通过boot烧录初始化程序&#xff0c;过程过于复杂&#xff0…

蓝桥杯省赛无忧 课件125 线段树-标记永久化

前置知识 线段树 01 什么是标记永久化 02 如何标记永久化 03 标记永久化的优势

【GAMES101】Lecture 17 材质

目录 材质 漫反射 镜面反射 折射-Snell’s Law Fresnel Reflection / Term&#xff08;菲涅耳项&#xff09; 微表面模型 各向同性与各向异性 BRDF的性质 测量BRDF 材质 渲染方程中的BRDF描述了物体是如何与光线作用的&#xff0c;而物体的材质决定了它看起来是怎么样…

「深度学习」门控循环单元GRU

一、梯度消失问题 梯度消失&#xff1a; 基础的 RNN 模型不善于处理长期依赖关系&#xff0c;有很多局部影响&#xff0c;很难调整自己前面的计算。y^{<i>} 仅仅受自己附近的值影响。 解决方法&#xff1a;GRU 或 LSTM 梯度爆炸&#xff1a; 反向传播时&#xff0c;随着…

基于A-Star搜索算法的迷宫小游戏的设计

这篇文章是作者人工智能导论课的大作业&#xff0c;发出来供大家学习参考&#xff08;有完整代码&#xff09;。想要论文WORD文件的可以在本文资源处下载&#xff08;可能还在审核&#xff09;。 摘要&#xff1a; 本文章聚焦于基于A-Star搜索算法的迷宫小游戏设计&#xff0c;…

[设计模式Java实现附plantuml源码~结构型]实现对象的复用——享元模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

前端基础复习(后端人员看前端知识)

企业级前端项目开发中&#xff0c;需要将前端开发所需要的工具、技术、流程、经验进行规范化和标准化&#xff0c;而不是零散的html、js、css文件堆叠在一起。 首先我们需配置前端的开发基础环境NodeJS&#xff0c;相当于后端人员java开发的JDK。然后搭建前端工程脚手架Vue-cl…