每日一题——滑动窗口的最大值

滑动窗口的最大值

题目链接


暴力解法

最容易想到的当然还是通过两层循环来暴力求解:一层循环用来移动窗口,一层循环用来在窗口内找到最大值。这种做法的时间复杂度为O(kN),会超出时间限制,因此,我们要找到更加高效的方法。

单调队列

注:这种解法建立在单调队列的基础之上,而单调队列是双端队列的特殊形式,如果对单调队列和双端队列还不太了解,建议先看看👉详解单调队列

由于我们要求的是滑动窗口的最大值,那我们不妨先做一个假设:如果当前的滑动窗口中有两个下标ij,其中**ij的左侧(i < j,并且i对应的元素不大于j对应的元素(nums[i] <= nums[j])**。

那么我们就可以得到这样一个结论:只要下标i所代表的元素nums[j]还在窗口中,那么下标j所对应的元素nums[j]也一定在窗口中,且**nums[i]一定不会是最大值**,也就不会对答案造成影响,我们也就可以将其直接删除

也可以用一句话来概括:

如果一个数据val要进入窗口,那他窗口内所有比它小或等于它的的数都不会对答案造成影响

我们可以用一个队列来存储这些还没有被移除的元素的下标,同时确保从队头到队尾,这些下标是从小到大排列的(保证数据的愿所有顺序),而下标所代表的值是递减排列的,这样队头元素就是滑动窗口的最大值了。

每当窗口向右滑动一个元素,就会有一个新的元素入队。在这个元素入队之前,由于我们要确保队列的单调递减性,因此当队列不为空并且队尾元素小于或等于新的元素时就要通过循环删除这些不会对结果造成影响的元素,最后再把这个元素的下标插入队列。

需要注意:当窗口向右滑动时,最大值下标会离开窗口,永远不会在进入窗口,因此在窗口滑动的过程中,我们要不断比较队首元素的下标(最大值下标)和窗口最左侧的标(下次移动时离开窗口的元素下标),如果离开了窗口,就要将队首元素出队。

例如对于上图的示例:

实现代码

typedef struct DequeNode
{
    struct DequeNode* next;
    struct DequeNode* prev;
    int data;
}DQNode;

typedef struct Deque
{
    DQNode* front;
    DQNode* tail;
}Deque;

void DequeInit(Deque* pq)   //双端队列初始化
{
    assert(pq);

    pq->front = pq->tail = NULL;
}

bool DequeEmpty(Deque* pq)  //双端队列判空
{
    assert(pq);

    return pq->front == NULL;
}

void DequePushTail(Deque* pq, int val)  //队尾入队
{
    DQNode* newNode = (DQNode*)malloc(sizeof(DQNode));
    newNode->data = val;
    newNode->next = NULL;
    newNode->prev = NULL;

    if (DequeEmpty(pq))
    {
        pq->front = pq->tail = newNode;
    }
    else
    {
        pq->tail->next = newNode;
        newNode->prev = pq->tail;
        pq->tail = newNode;
    }
}

void DequePushFront(Deque* pq, int val) //队头入队
{
    DQNode* newNode = (DQNode*)malloc(sizeof(DQNode));
    newNode->data = val;
    newNode->next = NULL;
    newNode->prev = NULL;

    if (DequeEmpty(pq))
    {
        pq->front = pq->tail = newNode;
    }
    else
    {
        newNode->next = pq->front;
        pq->front->prev = newNode;
        pq->front = newNode;
    }
}

int DequePopFront(Deque* pq)    //队头出队
{
    assert(pq);
    assert(!DequeEmpty(pq));

    DQNode* temp = pq->front;
    int ret = temp->data;

    pq->front = pq->front->next;
    if (pq->front == NULL)
        pq->tail = NULL;
    else
        pq->front->prev = NULL;
    
    free(temp);
    return ret;
}

int DequePopTail(Deque* pq) //队尾出队
{
    assert(pq);
    assert(!DequeEmpty(pq));

    DQNode* temp = pq->tail;
    int ret = temp->data;

    pq->tail = pq->tail->prev;
    if (pq->tail == NULL)
        pq->front = NULL;
    else
        pq->tail->next = NULL;

    free(temp);
    return ret;
}

int DequeTail(Deque* pq)    //取队尾元素
{
    assert(pq);
    assert(!DequeEmpty(pq));

    return pq->tail->data;
}

int DequeFront(Deque* pq)   //取队头元素
{
    assert(pq);
    assert(!DequeEmpty(pq));

    return pq->front->data;
}

void DequeDestroy(Deque* pq)    //销毁双端队列
{
    while (!DequeEmpty(pq))
    {
        DQNode* temp = pq->front;
        pq->front = pq->front->next;

        free(temp);
    }

    free(pq);
}
//-------------------------------------双端队列基本功能实现-----------------------------------------------

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize){
    *returnSize = numsSize - k + 1;
    int* ret = (int*)malloc(sizeof(int) * (*returnSize));

    Deque* DQ_Max = (Deque*)malloc(sizeof(Deque));  //用来记录最大值下标

    DequeInit(DQ_Max);	//初始化

    //先将数组前k个入队列,构建初始窗口
    for (int i=0; i<k; i++)
    {
        //队列不为空且队尾元素小于或等于新元素,就将队尾元素删除
        //确保递减
        while (!DequeEmpty(DQ_Max) && nums[DequeTail(DQ_Max)] <= nums[i])
        {
            DequePopTail(DQ_Max);
        }

        DequePushTail (DQ_Max, i);	//将下标入队
    }

    ret[0] = nums[DequeFront(DQ_Max)];	//初始窗口的最大值就是队头下下标所代表的元素

    //再将后面剩余的元素下标入队
    for (int i=k; i<numsSize; i++)
    {
        //删除不在窗口的下标
        while (!DequeEmpty(DQ_Max) && DequeFront(DQ_Max) <= i - k)
            DequePopFront(DQ_Max);
        
        //队列不为空且队尾元素小于新元素,就将队尾元素删除
        //确保非递增
        while (!DequeEmpty(DQ_Max) && nums[DequeTail(DQ_Max)] <= nums[i])
        {
            DequePopTail(DQ_Max);
        }

        DequePushTail (DQ_Max, i);

        //窗口最大值就是队头下下标所代表的元素
        ret[i - k + 1] = nums[DequeFront(DQ_Max)];
    }

    //销毁队列,释放内存
    DequeDestroy(DQ_Max);

    return ret;
}

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

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

相关文章

UX与UI设计的区别是什么?看这一篇就够了!

在产品开发和用户体验设计领域&#xff0c;UX&#xff08;用户体验&#xff09;与UI&#xff08;用户界面&#xff09;设计是两个常被提及的概念&#xff0c;其本质都是在解决产品的用户问题&#xff0c;但在实际的工作场景中&#xff0c;它们代表着不同的设计方向与职责。 简…

自举电容的工作原理

一&#xff0e;异步自举 1.1异步Buck的自举环路组成 上图为芯片的典型应用拓扑&#xff0c;Cboot就是我们说的自举电容。为了能清楚的理解自举电容的原理&#xff0c;我们需要深入到Buck芯片内部&#xff0c;去看个究竟。 上图即为异步Buck芯片LMR16006的内部架构。 ①Q1&…

Git入门到精通——保姆级教程(涵盖GitHub、Gitee、GitLab)

文章目录 前言一、Git1.Git-概述1.1.Git-概述-版本控制介绍1.2.Git-概述-分布式版本控制VS集中式版本控制1.3.Git-概述-代码托管中心1.4.Git-概述-安装和客户端的使用 2.Git-命令(常用命令)2.1.Git-命令-设置用户签名2.2.Git-命令-初始化本地库2.3.Git-命令-查看本地库状态2.4.…

机器学习---梯度下降代码

1. 归一化 # Read data from csv pga pd.read_csv("pga.csv") print(type(pga))print(pga.head())# Normalize the data 归一化值 (x - mean) / (std) pga.distance (pga.distance - pga.distance.mean()) / pga.distance.std() pga.accuracy (pga.accuracy - pg…

数据库新闻速递 -- POSTGRESQL 正在蚕食数据库市场 (翻译)

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加 liuaustin3微信号 &#xff0c;在新加的朋友会分到3群&#xff…

C语言----输入scanf和输出printf详解

C语言编程中&#xff0c;输入输出是基本操作&#xff0c;printf和scanf并不是C语言中的唯一的输入输出选择&#xff0c;对于输入有scanf()、getchar()、getche()、getch()、gets()&#xff1b;对于输出有printf()、puts()、putchar()&#xff0c;他们各有自己的使用场景&#x…

tabBar的使用

参考Api&#xff1a;全局配置 | 微信开放文档 (qq.com) 1.使用说明 2.使用详情 3.使用案例 在全局配置的app.json中 "tabBar": {"color": "#333","selectedColor": "#d43c33","backgroundColor": "#fff&qu…

C++ 混合Python编程 及 Visual Studio配置

文章目录 需求配置环节明确安装的是64位Python安装目录 创建Console C ProjectCpp 调用 Python Demo 参考 需求 接手了一个C应用程序&#xff0c;解析csv和生成csv文件&#xff0c;但是如果要把多个csv文件合并成一个Excel&#xff0c;分布在不同的Sheet中&#xff0c;又想在一…

网络安全进阶学习第十五课——Oracle SQL注入

文章目录 一、Oracle数据库介绍二、Oracle和MySQL的语法差异&#xff1a;三、Oracle的数据库结构四、Oracle的重点系统表五、Oracle权限分类1、系统权限2、实体权限3、管理角色 六、oracle常用信息查询方法七、联合查询注入1、order by 猜字段数量2、查数据库版本和用户名3、查…

vue使用ElementUI

1.安装 npm i element-ui -S 2.引入 2.1完整引入 import Vue from vue; import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; import App from ./App.vue;Vue.use(ElementUI); 2.2按需引入 说明&#xff1a;为了输入时候有提示&#xff0c;建…

Oracle DB 安全性 : TDE HSM TCPS Wallet Imperva

• 配置口令文件以使用区分大小写的口令 • 对表空间进行加密 • 配置对网络服务的细粒度访问 TCPS 安全口令支持 Oracle Database 11g中的口令&#xff1a; • 区分大小写 • 包含更多的字符 • 使用更安全的散列算法 • 在散列算法中使用salt 用户名仍是Oracle 标识…

恒盛策略:沪指冲高回落跌0.26%,酿酒、汽车等板块走弱,燃气股拉升

10日早盘&#xff0c;两市股指盘中冲高回落&#xff0c;半日成交约4200亿元&#xff0c;北向资金净卖出超20亿元。 到午间收盘&#xff0c;沪指跌0.26%报3235.9点&#xff0c;深成指跌0.54%&#xff0c;创业板指跌0.28%&#xff1b;两市算计成交4202亿元&#xff0c;北向资金净…

【ArcGIS Pro二次开发】(60):按图层导出布局

在使用布局导图时&#xff0c;会遇到如下问题&#xff1a; 为了切换图层和导图方便&#xff0c;一般情况下&#xff0c;会把相关图层做成图层组。 在导图的时候&#xff0c;如果想要按照图层组进行分开导图&#xff0c;如上图&#xff0c;想导出【现状图、规划图、管控边界】3…

SaaS BI数据可视化工具:免下载安装,登录即分析

之前有人问我&#xff0c;说&#xff1a;“BI数据可视化工具总是要下载安装&#xff0c;过程繁琐&#xff0c;没点IT基础的人也不太搞得定&#xff0c;有没有不用下载安装就能用的数据可视化工具&#xff1f;”答案当然是有的&#xff0c;那就是SaaS BI数据可视化工具。 SaaS …

Selenium 根据元素文本内容定位

使用xpath定位元素时&#xff0c;有时候担心元素位置会变&#xff0c;可以考虑使用文本内容来定位的方式。 例如图中的【股市】按钮&#xff0c;只有按钮文本没变&#xff0c;即使位置变化也可以定位到该元素。 xpath内容样例&#xff1a; # 文本内容完全匹配 //button[text(…

@RequestHeader使用

RequestHeader 请求头参数的设置 GetMapping("paramTest/requestHeader")public String requestHeaderTest(RequestHeader("name") String name){return name;} 在Postman的Headers中添加请求头参数&#xff0c;不过貌似不能加中文

面对算力瓶颈,如何利用CPU解决全链路智能编码?

编者按&#xff1a;英特尔是半导体行业和计算创新领域的全球领先厂商。与合作伙伴一起&#xff0c;英特尔推动了人工智能、5G、智能边缘等转折性技术的创新和应用突破&#xff0c;驱动智能互联世界。不久前&#xff0c;英特尔正式发布了第四代英特尔至强可扩展处理器&#xff0…

css实现文字首行缩进的效果

<div class"content"><p>站在徐汇滨江西岸智塔45楼&#xff0c;波光粼粼的黄浦江一览无余。近处&#xff0c;是由龙华机场储油罐改造而来的油罐艺术中心和阿里巴巴上海总部办公处。远处&#xff0c;历史悠久的龙华塔挺拔秀丽&#xff0c;总投资逾600亿元…

nginx负载均衡与反向代理与正向代理

负载均衡&#xff1a;通过反向代理来实现 正向代理的配置方法。 正向代理&#xff1a; 工作原理&#xff1a;用户端直接访问不了&#xff0c;需要通过代理服务器来访问web服务器&#xff0c;用户端先访问代理服务器&#xff0c;再访问web服务器。web服务器响应给代理服务器&a…

面试热题(反转链表)

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 链表的题&#xff0c;大部分都可以用指针或者递归可以做&#xff0c;指针如果做不出来的话&#xff0c;…