LeetCode 热题100——单调栈

  个人主页:日刷百题

系列专栏〖C语言小游戏〗〖Linux〗〖数据结构〗 〖C语言〗

🌎欢迎各位点赞👍+收藏⭐️+留言📝 

 写在前面:

递增单调栈:栈中元素从栈底到栈顶依次增大
递减单调栈:栈中元素从栈底到栈顶依次减小

在学习完朴素的数据结构栈之后,单调栈作为栈的一种升级版应用,在某些情境下具有得天独厚的优越性:可将O(n²)的遍历复杂度降低至O(n)

以下就是几种经典的单调栈运用问题。

一、字符串解码 

 

 思路:这题利用了栈,但不是单调栈,我们看到括号问题容易联想到有效括号问题也是利用栈

(1)遍历字符数组,当没有遇到‘]’时,将字符全部入栈

(2)若遇到‘]’,将字母一一出栈,入到临时栈,直到遇到‘[’停止

(3)此时将'['出栈,此时栈顶必然是数字字符,将数字字符全部转化为mulsize数字,出栈

(4)用2层嵌套循环,外层为mulsize,内层为临时栈的元素个数,将临时栈元素按mulszie次循环放进栈中,最后将临时栈初始化

(5)最后,字符遍历结束,栈中元素即为所求,此时将栈的末尾加上’\0’.

注:这里值得注意的地方有俩点

<1>在栈末尾插入‘\0’,得有扩容判断

<2>在将数字字符转化为mulsize时,字符数字是一个个出栈,为逆序,例如:100出栈为001,所以转化为数字的时候,要注意

typedef char DateType;
typedef struct Stack
{DateType* a;int top;int capacity;
}Stack;
//初始化和销毁栈
void InitStack(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = ps->capacity = 0;
}
void DestoryStack(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}//出栈和入栈
void StackPush(Stack* ps, DateType x)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;DateType* tmp = (DateType*)realloc(ps->a, sizeof(DateType) * newcapacity);if (tmp == NULL){perror("realloc fail:");return;}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = x;ps->top++;
}
void StackPop(Stack* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}//栈的有效个数和栈顶元素
int StackSize(Stack* ps)
{assert(ps);return ps->top;
}
DateType StackTop(Stack* ps)
{assert(ps);assert(ps->top > 0);return   ps->a[ps->top - 1];
}
//判空
bool IsEmptyStack(Stack* ps)
{assert(ps);return ps->top == 0;
}
char* decodeString(char* s) {Stack ps;Stack tmp;InitStack(&ps);InitStack(&tmp);int len = strlen(s);while ((*s) != '\0'){if ((*s) != ']'){StackPush(&ps, (*s));}else{while (StackTop(&ps) != '['){char b = StackTop(&ps);StackPop(&ps);StackPush(&tmp, b);}StackPop(&ps);int tmpsize = tmp.top;int mulsize=0;int i=0;while (ps.top > 0 && ps.a[ps.top - 1] >= '0' && ps.a[ps.top - 1] <= '9'){mulsize =mulsize  + pow(10,i)*(ps.a[ps.top - 1] - '0');StackPop(&ps);i++;}for (int i = 0; i < mulsize; i++){for (int j = 0; j < tmpsize; j++){char w = StackTop(&tmp);StackPush(&ps, w);StackPop(&tmp);}tmp.top = tmpsize;}}if (tmp.a != NULL){free(tmp.a);tmp.a = NULL;InitStack(&tmp);}s++;}DestoryStack(&tmp);if (ps.top == ps.capacity){int newcapacity = ps.capacity == 0 ? 4 : 2 * ps.capacity;DateType* tmp = (DateType*)realloc(ps.a, sizeof(DateType) * newcapacity);if (tmp == NULL){perror("realloc fail:");return 1;}ps.a = tmp;ps.capacity = newcapacity;}ps.a[ps.top] = '\0';return ps.a;
}

 二、接雨水

思路:这题思路比较巧妙,运用了单调递减栈

(1)创造栈用来存放数组元素下标

(2)遍历数组,若栈为空或者栈顶元素所对应的数组值大于等于数组元素,则直接入栈

(3)若栈顶元素所对应数组元素值小于数组元素,则做出判断,将栈顶元素保存,且出栈,再用此时的栈顶元素所对应的数组值与数组元素比较,俩个数的较小值减去原来保存的栈顶元素所对应数组值即为接雨水凹槽的高,此时数组下标与栈顶差值减1即为接雨水凹槽的宽,相乘即为所接雨水的面积,保持循环,直到栈为空或者栈为递减,退出循环,进行数组下一个元素比较。

上面思路听起来比较复杂,可以看图理解:

typedef int DateType;
typedef struct  Stack
{DateType* a;int top;int capacity;
}Stack;
//初始化和销毁
void InitStack(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = ps->capacity = 0;
}
void DestroyStack(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
//出栈和入栈
void StackPush(Stack* ps, DateType x)
{assert(ps);if(ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 4;DateType* tmp = (DateType*)realloc(ps->a,sizeof(DateType) * newcapacity);if (tmp == NULL){perror("realloc fail:");return;}ps->capacity = newcapacity;ps->a = tmp;}ps->a[ps->top] = x;ps->top++;}
void StackPop(Stack* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}
//栈顶元素和元素个数
int StackSize(Stack* ps)
{assert(ps);return  ps->top;
}
DateType StackTop(Stack* ps)
{assert(ps);assert(ps->top > 0);return ps->a[ps->top - 1];
}//判空
bool  IsEmptyStack(Stack* ps)
{assert(ps);return ps->top == 0;
}
int MIN(int x, int y)
{return x > y ? y : x;
}
int trap(int* height, int heightSize) {Stack ps;InitStack(&ps);int count = 0;for (int i = 0; i < heightSize; i++){while (ps.top > 0 && height[StackTop(&ps)] < height[i]){DateType tmp = StackTop(&ps);StackPop(&ps);if (ps.top == 0){break;}int h = MIN(height[StackTop(&ps)], height[i]);int width = i - StackTop(&ps) - 1;count += (h - height[tmp]) * width;}StackPush(&ps, i);}DestroyStack(&ps);return count;
}

三、每日温度 

 

 思路:这题思路比较巧妙,运用了单调递减栈和上面一题类似

(1)创造栈用来存放数组元素下标

(2)遍历数组,若栈为空或者栈顶元素所对应的数组值大于等于数组元素,则直接入栈

(3)若栈顶元素所对应数组元素值小于数组元素,则做出判断,将栈顶元素保存,且出栈,由于当前数组元素大于栈顶元素对应数组元素值,而且一定是第一个大于栈顶元素对应数组元素值,直接求出下标差(当前数组元素下标和栈顶元素差)就是二者的距离,放入所求目标数组内(数组下标为保存的栈顶元素)。继续看新的栈顶元素,循环往复,直到当前数组元素小于等于栈顶元素所对应数组值或者栈为空停止,然后将数组元素下标入栈,进行数组下一个元素比较

(3)数组遍历结束后,栈为单调递减栈,里面元素所对应数组值(气温)向后检索找不到比它高的温度,所以以这些栈元素为下标的目标数组元素全部置为0.

图解如下:

typedef int DateType;
typedef struct  Stack
{DateType* a;int top;int capacity;
}Stack;
//初始化和销毁
void InitStack(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = ps->capacity = 0;
}
void DestroyStack(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
//出栈和入栈
void StackPush(Stack* ps, DateType x)
{assert(ps);if(ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 4;DateType* tmp = (DateType*)realloc(ps->a,sizeof(DateType) * newcapacity);if (tmp == NULL){perror("realloc fail:");return;}ps->capacity = newcapacity;ps->a = tmp;}ps->a[ps->top] = x;ps->top++;}
void StackPop(Stack* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}
//栈顶元素和元素个数
int StackSize(Stack* ps)
{assert(ps);return  ps->top;
}
DateType StackTop(Stack* ps)
{assert(ps);assert(ps->top > 0);return ps->a[ps->top - 1];
}//判空
bool  IsEmptyStack(Stack* ps)
{assert(ps);return ps->top == 0;
}int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize) {int *answer=(int *)malloc(sizeof(int)*temperaturesSize);Stack  st;InitStack(&st);for(int i=0;i<temperaturesSize;i++){while(st.top>0&&temperatures[i]>temperatures[StackTop(&st)]){answer[StackTop(&st)]=i-StackTop(&st);StackPop(&st);if(st.top==0){break;}}StackPush(&st,i);}while(st.top>0){answer[StackTop(&st)]=0;StackPop(&st);}* returnSize=temperaturesSize;return answer;}

四、柱状图中最大的矩形 

 

思路:这题思路与接雨水问题一样,不过此题用的是严格单调增栈 

(1)创造栈用来存放数组元素下标

(2)遍历数组,若栈为空或者栈顶元素所对应的柱形高度小于当前柱形高度,则当前柱形高度的数组下标直接入栈

(3)若栈顶元素所对应数组元素值大于等于数组元素,则做出判断,将栈顶元素临时保存,且出栈,再用当前数组元素下标与栈顶元素做差-1即为临时保存的栈顶元素所对应柱形高度的宽,根据原来临时保存栈顶元素求出其对应的高,就可以求出该高度的最大矩形面积,,保持循环,直到栈为空或者栈为严格递增,退出循环,进行数组下一个元素比较。

(4)数组遍历结束,栈为严格单调递增栈,除了最后一个栈底元素外,其他栈元素对应柱形高度最大矩形宽度为数组长度减去当前栈元素左侧一个栈元素的值-1,栈底元素对应柱形高度最大矩形宽度为数组元素长度

注:这里面有几个注意的细节

<1>当栈元素为1个,且数组元素小于等于栈顶对应柱形高度,此时临时保存栈顶元素,出栈,此临时保存栈顶元素对应柱形高度所能扩展做大矩形宽度为:当前数组元素下标i减去临时保存的栈顶元素

<2>数组元素等于栈顶栈顶对应柱形高度时,虽然所求的最大矩形不是这个栈顶的最大矩形,但是要小于这个栈顶元素对应的最大矩形面积,不碍事,直到下一个数组元素严格小于栈顶元素对应柱形高度,此时所求的最大矩形面积即之前那个相等高度的最大矩形面积,所以不影响

图解如下:

typedef int DateType;
typedef struct  Stack
{DateType* a;int top;int capacity;
}Stack;
//初始化和销毁
void InitStack(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = ps->capacity = 0;
}
void DestroyStack(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
//出栈和入栈
void StackPush(Stack* ps, DateType x)
{assert(ps);if(ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 4;DateType* tmp = (DateType*)realloc(ps->a,sizeof(DateType) * newcapacity);if (tmp == NULL){perror("realloc fail:");return;}ps->capacity = newcapacity;ps->a = tmp;}ps->a[ps->top] = x;ps->top++;}
void StackPop(Stack* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}
//栈顶元素和元素个数
int StackSize(Stack* ps)
{assert(ps);return  ps->top;
}
DateType StackTop(Stack* ps)
{assert(ps);assert(ps->top > 0);return ps->a[ps->top - 1];
}//判空
bool  IsEmptyStack(Stack* ps)
{assert(ps);return ps->top == 0;
}
int  MAX(int x, int y)
{return x>y?x:y;
}int largestRectangleArea(int* heights, int heightsSize) {Stack st;InitStack(&st);int max = 0;for (int i = 0; i < heightsSize; i++){while (st.top>0 && heights[i] <= heights[StackTop(&st)]){int tmp = StackTop(&st);StackPop(&st);if(st.top==0){max=MAX(max, heights[tmp]*i);break;}int width = i - StackTop(&st) - 1;max = MAX(max, heights[tmp] * width);}StackPush(&st, i);//严格单调增}//遍历结束后,变为严格单调递增栈while (st.top>0){int tmp =StackTop(&st);StackPop(&st);if (st.top==0){max = MAX(max, heights[tmp] * heightsSize);break;}int width = heightsSize - StackTop(&st)-1 ;max = MAX(max, heights[tmp] * width);}return max;}

 总结:本篇文章讲解了单调栈的应用,为系列题目,有利于帮助理解单调栈的用法和这系列问题思路。

希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,百题一定会认真阅读!

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

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

相关文章

3D模型人物换装系统(二 优化材质球合批降低DrawCall)

3D模型人物换装系统 介绍原理合批材质对比没有合批材质核心代码完整代码修改总结 介绍 本文使用2018.4.4和2020.3.26进行的测试 本文没有考虑法线贴图合并的问题&#xff0c;因为生成法线贴图有点问题&#xff0c;放在下一篇文章解决在进行优化 如果这里不太明白换装的流程可以…

HarmonyOS引导页登陆页以及tabbar的代码说明1

效果 以下代码是东拼西凑出来的。只是为了个人熟悉一下相关模块的使用&#xff1a; 用的知识点&#xff1a; Resouces 此部分分内容可以在项目中找到&#xff1a; resources/base/element/color.json 为项目着色配置&#xff0c;当然也可以正接在代码里写 float.json 为相关…

IPv6路由基础-理论与配置

在企业网络中&#xff0c;IPv6技术的应用越来越普及。IETF组织针对IPv6网络制定了路由协议OSPFv3。 OSPFv3 ff02::5是为OSPFv3路由协议预留的IPv6组播地址。OSPFv3中的路由条目下一跳地址是链路本地地址。OSPFv3是运行在IPv6网络的OSPF协议。运行OSPFv3的路由器使用物理接口的…

华为云Stack 8.X 流量模型分析(一)

一、基础知识 1.tap与tun ​ tap与tun都是操作系统&#xff08;Linux&#xff09;内核中的虚拟网络设备&#xff0c;等同于一个以太网设备&#xff0c;可以收发数据报文包。 ​ tap与tun的定义相同&#xff0c;两者仅仅是通过一个Flag来区分。但二者所承担的功能差别较大&am…

centos磁盘扩容

[rootlocalhost ~]# fdisk -l磁盘 /dev/sda&#xff1a;429.5 GB, 429496729600 字节&#xff0c;838860800 个扇区 Units 扇区 of 1 * 512 512 bytes 扇区大小(逻辑/物理)&#xff1a;512 字节 / 4096 字节 I/O 大小(最小/最佳)&#xff1a;4096 字节 / 4096 字节 磁盘标签类…

浅析 fuse kernel mmap write 过程及性能问题

前言 最近在项目里面用到了fuse文件系统&#xff0c;在使用过程中遇到了一个内核在做mmap write的一个bug&#xff0c;目前并没有从根本上解决这个bug&#xff0c;而是通过修改fuse kernel module的一些参数&#xff0c;绕开了这个bug。这里记录一下这个问题&#xff0c;并顺便…

信息收集 - 网站敏感信息

CMS指纹信息: CMS (内容管理系统)又称为整站系统或文章系统,用于网站内容管理。用户只需要下载对应的CMS软件包,就能部署搭建,并直接利用CMS。但是各种CMS都具有其独特的结构命名规则和特定的文件内容,因此可以利用这些内容来获取CMS站点的具体软件CMS与版本。通过识别CMS…

手把手教你在windows上安装Portainer

前言 大家好&#xff0c;我是潇潇雨声。在之前的文章中&#xff0c;我们探讨了在 Windows 上安装 Docker 的方法。今天&#xff0c;我将简要介绍一个开源的轻量级容器管理工具——Portainer&#xff0c;它类似于 navicat。Portainer 是一个与 navicat 类似的工具&#xff0c;但…

facebook广告怎么效果好

要提高Facebook广告的效果&#xff0c;可以尝试以下策略&#xff1a; 明确广告目标&#xff1a;在制定广告计划之前&#xff0c;需要明确广告的目标。这可能包括增加网站流量、提高品牌知名度、推广新产品或提高现有产品的销售量。明确目标后&#xff0c;可以制定相应的广告策…

Amazon Toolkit — CodeWhisperer 使用

tFragment--> 官网&#xff1a;https://aws.amazon.com/cn/codewhisperer/?trkcndc-detail 最近学习了亚马逊云科技的 代码工具&#xff0c;感慨颇多。下面是安装 和使用的分享。 CodeWhisperer&#xff0c;亚马逊推出的实时 AI 编程助手&#xff0c;是一项基于机器学习…

前端八股文(vue篇)

一.vue中的key的作用 key的作用主要是为了高效的更新虚拟dom。另外vue中在使用相同标签名元素的过渡切换时&#xff0c;也会使用到key属性&#xff0c;其目的也是为了让vue可以区分它们&#xff0c;否则vue只会替换内部属性而不会触发过渡效果。 二.接口请求一般放在哪个生命周…

详解数据科学自动化与机器学习自动化

过去十年里&#xff0c;人工智能&#xff08;AI&#xff09;构建自动化发展迅速并取得了多项成就。在关于AI未来的讨论中&#xff0c;您可能会经常听到人们交替使用数据科学自动化与机器学习自动化这两个术语。事实上&#xff0c;这些术语有着不同的定义&#xff1a;如今的自动…

【QT Visual Studio环境配置】error MSB8020: 无法找到 v141/v142 的生成工具(完整版)

首先要了解V**平台工具集根据你安装的Visual Studio版本不同而有所区别&#xff0c;知道这个就容易解决问题了&#xff0c;确定你安装的那个版本&#xff0c;需要使用哪个工具集。 v143–>VS2022v142–>VS2019v141–>VS2017v140–>VS2015v120–>VS2013 一、解决…

[kubernetes]基于版本v1.28.5+containerd + helm 搭建集群

0 环境准备 节点数量: 3 台虚拟机 centos7硬件配置: 2G或更多的RAM&#xff0c;2个CPU或更多的CPU&#xff0c;硬盘至少30G 以上网络要求: 多个节点之间网络互通&#xff0c;每个节点能访问外网 1 集群规划 k8s-node1&#xff1a;10.0.0.32k8s-node2&#xff1a;10.0.3.231k…

TypeScript 中的 interface 和 type 有什么区别?应该如何选择?

背景 TypeScript中的 interface 和 type 都是声明自定义类型的方式&#xff0c;但它们有一些区别&#xff0c;适用于不同的使用场景。 两者使用案例 interface interface 主要用于描述对象的形状或者类的结构&#xff0c;这是它最经常的应用场景。 interface使用示例&…

机器学习之线性回归(Linear Regression)附代码

概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…

MySQL:通过官方mysql server,搭建绿色版mysql服务器(Windows)

1. 官网下载mysql server 下载mysql server的zip文件&#xff0c;地址&#xff1a; https://downloads.mysql.com/archives/community/ 解压后 2. 初始化数据库 运行cmd&#xff0c; 进入bin目录&#xff0c;运行 mysqld --initialize-insecureinitialize-insecure说明如…

python面向对象反射

就是通过字符串的形式操作对象相关属性 反射基本语法 from django.test import TestCase# Create your tests here. class Students:def __init__(self, name, gender):self.name nameself.gender genderdef play(self, game, novel):print(game, novel)s Students(lyz, …

Jenkins 插件下载速度慢安装失败?这篇文章可能解决你头等难题!

Jenkins部署完毕&#xff0c;如果不安装插件的话&#xff0c;那它就是一个光杆司令&#xff0c;啥事也做不了&#xff01; 所以首先要登陆管理员账号然后点击系统管理再点击右边的插件管理安装CI/CD必要插件。 但是问题来了&#xff0c;jenkins下载插件速度非常慢&#xff0c…

Educational Codeforces Round 160 (Div. 2) A~E

A.Rating Increase&#xff08;思维&#xff09; 题意&#xff1a; 给出一个仅包含数字的字符串 s s s&#xff0c;要求将该字符串按以下要求分成左右两部分 a , b a,b a,b&#xff1a; 两个数字均不包含前导 0 0 0 两个数字均大于 0 0 0 b > a b > a b>a 如果…