stack栈练习

为了你,我变成狼人模样;

为了你,染上了疯狂~

目录

  • stack栈练习
      • 括号的分数
    • 单调栈
      • 模板框架
      • 小结
      • 下一个更大元素 I(单调栈+哈希)
      • 接雨水

stack栈练习

一种先进后出的线性数据结构

具体用法可参考往期文章或者维基介绍i

对应简易练习

20. 有效的括号 - 力扣(LeetCode)

32. 最长有效括号 - 力扣(LeetCode)

括号的分数

856. 括号的分数 - 力扣(LeetCode)

本题主要是为了计算平衡括号字符串的分数,利用栈模拟并计算分数。遍历字符串,在遇到右括号时根据最近匹配情况更新分数。

法一:利用栈,遍历字符处理

左括号 (:压入新的 0 作为当前层的分数占位符

右括号 )

  • 弹出栈顶值 v(最近未匹配括号计算的分数)
  • 分类更新分数:
    • v=0:最近是未匹配的左括号,形成 () 得1分
    • v>0:最近是已匹配括号组,形成 (A)2v
  • 将计算出的分数累加到新的栈顶(上一层)

利用栈可以记录每层括号的中间分数,又因为他是先进后出的结构所以可以自动处理嵌套的关系,栈顶始终保存当前层的结果;遍历完后最终栈顶即为整个字符串的总分;

class Solution {
public:int scoreOfParentheses(string s) {stack<int> st;st.push(0);for (auto c : s) {if (c == '(') {st.push(0);} else {int v=st.top();st.pop();if(v==0)st.top()+=1;elsest.top()+=v<<1;}}return st.top();}
};

法二:利用栈的思想,分层级处理(有点类似于后缀表达式)

仔细观察,不难发现,题目中给出的字符串可匹配一定是合理的;所以每经历到一次(就相当于进入了一个新的层级(触发了嵌套关系)而遇到)就相当于退出了一个层级(结束嵌套);而遇到一个完整的()就是一个单位1,判断这个单位1处在那个层级累加到结果中(因为每个单独的()是相加的关系)即为所求;

这个方法通过维护一个动态乘数 n 来计算分数,核心思想是将嵌套括号转化为深度相关的乘数累计

初始

  • n=1 作为基础乘数(对应嵌套深度0)(n 表示当前括号所在深度的分数倍率)
  • an=0 作为总分累加器

遍历字符串

  • 左括号 (
    • 将乘数 n 左移一位(n <<= 1),相当于乘数加倍(进入下一层)
  • 右括号 )
    • 将乘数 n 右移一位(n >>= 1),相当于恢复上层乘数(退出当前层)
    • 判断:如果当前)与前一个字符形成()
      • 将当前乘数 n 累加到总分 an
class Solution {
public:int scoreOfParentheses(string s) {int n=1,an=0;for(int i=0;i<s.size();i++){if(s[i]=='(')n<<=1;elsen>>=1;if(s[i]==')'&&s[i-1]=='(')an+=n;}return an;}
};

和法一相比时间复杂度差不多(O(n)),都需要遍历一次字符串;但是空间复杂度从原先的O(n)(栈空间)降低到了O(1)(常数空间);


单调栈

单调栈,你不乘哦

何为单调栈?顾名思义,单调栈即满足单调性的栈结构。与单调队列相比,其只在一端进行进出。

将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素。

原理:维护一个栈,保持栈内元素单调递减。当处理新元素时,弹出所有比它小的元素,这些被弹出的元素与新元素形成一定的关系。

使用场景:适用于需要找到每个元素左边或右边第一个比它大或小的元素的问题。

实现步骤:
初始化空栈
对于每个元素:
弹出栈中所有比当前元素小的元素(这些元素能被当前元素看到)
计算当前元素能被栈中剩余元素看到的数量(即栈的大小)
将当前元素压入栈

while(栈顶元素比入栈元素小或大 && 栈不空)
{栈顶元素弹出
}
元素入栈

模板框架

P5788 【模板】单调栈 - 洛谷

最基础的模板题,需要我们寻找序列中每个元素"下一个更大元素"的位置(下标)

维护单调性使用栈维护"尚未找到下一个更大元素"的下标,保持栈底到栈顶对应的元素值单调递减,当新元素a[i]比栈顶对应元素大时,说明新元素是栈顶元素的"下一个更大元素"

从左到右遍历一遍序列

  • a[i] > 栈顶对应元素 → 弹出栈顶并记录答案
  • 当前下标i入栈(等待后续元素为其寻找更大值)

遍历结束后栈中剩余的元素(无更大元素),答案默认为0

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
const int N=1e7;
int a[N],an[N];
stack<int> s;
void slove(){int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){if(s.size()==0){s.push(i);continue;}if(a[i]>a[s.top()]){while(s.size()&&a[i]>a[s.top()]){an[s.top()]=i;s.pop();}}s.push(i);}for(int i=1;i<=n;i++)cout<<an[i]<<' ';
} 
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;//cin>>_;while(_--)slove();return 0;
}

同类型的套用模板的题目还有

739. 每日温度 - 力扣(LeetCode)

[P2866 [USACO06NOV] Bad Hair Day S - 洛谷](https://www.luogu.com.cn/problem/P2866)

时间复杂度:O ( n ),每个元素最多入栈和出栈一次。
空间复杂度:O ( n ),最坏情况下所有元素都在栈中。


小结

单调栈是解决"第一个比当前元素大/小"这类问题的有效工具。本题通过维护一个单调递增栈,保证了每个元素都能在O(1)均摊时间内找到左边第一个比它小的数。关键在于理解为什么可以安全地弹出那些不会影响后续结果的元素,从而保持栈的单调性。

这种算法思想在很多场景下都有应用,比如计算直方图的最大矩形面积、求解滑动窗口最大值等问题。掌握单调栈的使用可以大大提高解决这类问题的效率。


下一个更大元素 I(单调栈+哈希)

496. 下一个更大元素 I - 力扣(LeetCode)

本题需要为 nums1 中的每个元素在 nums2 中寻找下一个更大的元素(Next Greater Element)。核心思路是利用单调栈高效解决,并结合哈希表存储结果。

1.遍历 nums2 时维护一个递减栈(栈底到栈顶元素递减):

当前元素 i 若小于等于栈顶,直接入栈。

当前元素 i 若大于栈顶,则 i 是栈顶元素的下一个更大元素。此时将栈顶弹出并记录映射 mp[栈顶] = i,直到栈顶不小于 i 或栈空。

结果:栈中最后剩余的元素在 nums2 中无下一个更大元素。

2.哈希表记录映射

使用 unordered_map<int, int> mp 存储 nums2 中元素的下一个更大元素。

当元素被弹出栈时,其下一个更大元素被记录(即触发弹出操作的元素)。

3.最后处理 nums1 的结果,找到每个对应的i即可

class Solution {
public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {vector<int> a;unordered_map<int,int> mp;stack <int> s;for(auto i:nums2){if(s.size()==0){s.push(i);continue;}while(s.size()&&i>s.top()){mp[s.top()]=i;s.pop();}s.push(i);}for(auto i:nums1){if(mp[i]==0)a.push_back(-1);elsea.push_back(mp[i]);}return a;}
};

接雨水

42. 接雨水 - 力扣(LeetCode)

本题要求计算柱状图中能接的雨水量。每个位置的存水量受短边的影响;可以直接套用单调栈求解,这里写出另外的两种解法;

法一:动态规划法

核心思路是通过构建左右方向的最大值数组,从而得到每个位置的理论盛水高度,最后减去实际柱高总和即得雨水总量。

  • 复制原始数组 b = a
  • 计算原始数组总和 ss(柱体总面积)

然后从两个方向遍历数组,维护两个单调的数组

让后计算理论盛水总量

  • 每个位置能盛水的理论高度:min(a[i], b[i])
  • 累加所有位置的理论高度:s += min(a[i], b[i])

计算实际雨水总量

  • 雨水总量 = 理论盛水总量 - 柱体总面积
  • return s - ss

最终呈现的时间复杂度为O(3n)

class Solution {
public:int trap(vector<int>& a) {vector<int> b=a;int ss=0;for(auto i:a)ss+=i;for(int i=1;i<a.size();i++)if(a[i]<a[i-1])a[i]=a[i-1];for(int i=b.size()-2;i>=0;i--)if(b[i]<b[i+1])b[i]=b[i+1];int s=0;for(int i=0;i<a.size();i++){s+=min(a[i],b[i]);}return s-ss;}
};

法二:双指针逐层计算

核心策略是逐层水平累加雨水面积。通过从高度1开始逐步增加水平面,利用双指针实时扫描有效容器边界,计算每一层可容纳的雨水宽度,最后减去柱体本身面积得到最终雨水总量。

  • 双指针:l=0(左边界),r=size-1(右边界)
  • 当前高度:h=1(从最低水位开始)
  • 盛水轮廓面积:s=0(包括水和柱子的总面积)

逐层累加(当l<=r时循环)

  • 找左边界:跳过所有高度小于当前层高h的柱子

    while (l < r && a[l] < h) l++;
    

    检查终止条件:当左右指针相遇(l==r)且该处高度小于h时,退出循环

  • 找右边界:跳过所有高度小于当前层高h的柱子

    while (l <= r && a[r] < h) r--;
    
  • 计算当前层宽:累加左右边界间的宽度s += (r - l + 1)

最终雨水总量 = 盛水轮廓面积s - 柱子总面积ss

但是这个方法的时间复杂度为O(n·H),在最大高度H较小时使用比较好;空间相比上个有所减少;

class Solution {
public:int trap(vector<int>& a) {if (a.empty())return 0;int l = 0, r = a.size() - 1;int h = 1;int s = 0;while (l<=r) {while (l < r && a[l] < h) {l++;}if (l == r) {if (a[l] < h)break;}while (l <= r && a[r] < h) {r--;}if (l > r)break;s += (r - l + 1);h++;}int ss = 0;for (auto i : a) {ss += i;}return s - ss;}
};

类似练习

84. 柱状图中最大的矩形 - 力扣(LeetCode)求内部的面积(计算直方图的最大矩形面积)


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

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

相关文章

详细页智能解析算法:洞悉海量页面数据的核心技术

详细页智能解析算法&#xff1a;突破网页数据提取瓶颈的核心技术剖析引言&#xff1a;数字时代的数据采集革命在当今数据驱动的商业环境中&#xff0c;详细页数据已成为企业决策的黄金资源。无论是电商商品详情、金融公告还是新闻资讯&#xff0c;​​有效提取结构化信息​​直…

ubuntu环境如何安装matlab2016

一、下载安装文件&#xff08;里面包含激活包CRACK&#xff09;可从度盘下载&#xff1a;链接:https://pan.baidu.com/s/1wxmVMzXiSY4RIT0dyKkjZg?pwd26h6 复制这段内容打开「百度网盘APP 即可获取」注&#xff1a;这里面包含三个文件&#xff0c;其中ISO包含安装文件&#x…

Mybits-plus 表关联查询,嵌套查询,子查询示例演示

在 MyBatis-Plus 中实现表关联查询、嵌套查询和子查询&#xff0c;通常需要结合 XML 映射文件或 Select 注解编写自定义 SQL。以下是具体示例演示&#xff1a;示例场景 假设有两张表&#xff1a; 用户表 userCREATE TABLE user (id BIGINT PRIMARY KEY,name VARCHAR(50),age IN…

Stable Diffusion Web 环境搭建

默认你的系统Ubuntu、CUDA、Conda等都存在&#xff0c;即具备运行深度学习模型的基础环境 本人&#xff1a;Ubuntu22.04、CUDA11.8环境搭建 克隆项目并且创建环境 https://github.com/AUTOMATIC1111/stable-diffusion-webui conda create -n sd python3.10运行过程自动安装依赖…

嵌入式系统中实现串口重定向

在嵌入式系统中实现串口重定向&#xff08;将标准输出如 printf 函数输出重定向到串口&#xff09;通常有以下几种常用方法&#xff0c;下面结合具体代码示例和适用场景进行说明&#xff1a; 1. 重写 fputc 函数&#xff08;最常见、最基础的方法&#xff09; 通过重写标准库中…

static补充知识点-代码

public class Student {private static int age;//静态的变量private double score;//非静态的方法public void run(){}public static void go(){}public static void main(String[] args) {new Student().run();Student.go();} } public class Person {//2 &#xff1a; 赋初始…

使用泛型<T>,模块化,反射思想进行多表数据推送

需求&#xff1a;有13个表&#xff0c;其中一个主表和12细表&#xff0c;主表用来记录推送状态&#xff0c;细表记录12种病例的详细信息&#xff0c;现在需要把这12张病例表数据进行数据推送&#xff1b;普通方法需要写12个方法分别去推送数据然后修改状态&#xff1b;现在可以…

光流 | RAFT光流算法如何改进提升

RAFT(Recurrent All-Pairs Field Transforms)作为ECCV 2020最佳论文,已成为光流估计领域的标杆模型。其通过构建4D相关体金字塔和GRU迭代优化机制,在精度与泛化性上实现了突破。但针对其计算效率、大位移处理、跨场景泛化等问题,研究者提出了多维度改进方案,核心方向可系…

linux/ubuntu日志管理--/dev/log 的本质与作用

文章目录 **一、基本概念****二、技术细节:UNIX域套接字****三、在不同日志系统中的角色****四、应用程序如何使用 `dev/log`****五、查看和验证 `/dev/log`****六、总结 `/dev/log` 的核心作用**一、基本概念 /dev/log 是一个 UNIX域套接字(Unix Domain Socket),是Linux系…

EMC整改案例之(1):汽车NFC进入模块BCI整改

EMC整改案例(1):汽车NFC进入模块BCI整改 在汽车电子系统中,NFC(Near Field Communication)进入模块用于实现无钥匙进入功能,但它在电磁兼容(EMC)测试中常面临挑战。本案例聚焦于BCI(Bulk Current Injection)测试整改,该测试模拟大电流注入对设备的影响。以下是基于…

2025年INS SCI2区,灵活交叉变异灰狼算法GWO_C/M+集群任务调度,深度解析+性能实测

目录1.摘要2.灰狼算法GWO原理3.灵活交叉变异灰狼算法GWO_C/M4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流1.摘要 随着云计算的快速发展&#xff0c;受自然现象启发的任务调度算法逐渐成为研究的热点。灰狼算法&#xff08;GWO&#xff09;因其强大的收敛性和易于…

Java常用加密算法详解与实战代码 - 附可直接运行的测试示例

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

2025开发者工具链革命:AI赋能的效率跃迁

目录引言&#xff1a;效率焦虑下的开发者生存现状一、智能代码编辑器&#xff1a;从辅助到主导的进化1.1 GitHub Copilot&#xff1a;全能型AI助手1.2 Cursor Pro&#xff1a;极致编码体验1.3 飞算JavaAI&#xff1a;垂直领域颠覆者二、版本控制革命&#xff1a;Git的AI进化论2…

“虚空”的物理、哲学悖论

一、虚空并非“完全真空”&#xff1a;量子场论揭示的“真空不空” 物理真空的本质 现代物理学中的“真空”并非绝对的空无一物&#xff0c;而是量子场的基态&#xff08;能量最低状态&#xff09;。根据量子场论&#xff1a; 虚粒子涨落&#xff1a;真空中持续发生量子涨落&am…

CSP-S模拟赛二总结(实际难度大于CSP-S)

T1 很简短&#xff0c;也很好做&#xff0c;第一题直接场切。 我的方法 首先要明确一件事&#xff1a;就是如果选了 ax,ya_{x,y}ax,y​&#xff0c;那么就必然要选 ay,xa_{y,x}ay,x​&#xff0c;所以第一步就在 ax,ya_{x,y}ax,y​ 的基础上加上 ay,xa_{y,x}ay,x​。 然后我…

旋转屏幕优化

1.问题背景 从google原生算法&#xff0c;可以知道其有2个比较大的缺陷&#xff1a; 1) 通过重力传感器传来的x&#xff0c;y&#xff0c;z轴的加速度合成之后只有一个垂直往下的加速度&#xff0c;如果此时用户在别的方向上有加速度&#xff0c;那么通过反余弦、反正切等计算…

Java---day2

七、IDEA开发工具 &#x1f4e6; 一、下载 IntelliJ IDEA 官网地址&#xff1a; &#x1f517; IntelliJ IDEA – the IDE for Pro Java and Kotlin Development 版本选择&#xff1a; 版本说明Community Edition (CE)免费开源版本&#xff0c;适合 Java、Kotlin、Android…

RAL-2025 | 清华大学数字孪生驱动的机器人视觉导航!VR-Robo:面向视觉机器人导航与运动的现实-模拟-现实框架

作者&#xff1a; Shaoting Zhu, Linzhan Mou, Derun Li, Baijun Ye, Runhan Huang, Hang Zhao单位&#xff1a;清华大学交叉信息研究院&#xff0c;上海期智研究院&#xff0c;Galaxea AI&#xff0c;上海交通大学电子信息与电气工程学院论文标题&#xff1a;VR-Robo: A Real-…

碰一碰发视频 + 矩阵系统聚合平台源码搭建,支持OEM

随着短视频生态与多平台运营需求的融合&#xff0c;“碰一碰发视频 矩阵系统” 聚合平台成为内容创作者与企业营销的新基建。这类系统需实现近场交互触发、多平台内容分发、数据聚合分析的全流程闭环&#xff0c;其源码搭建与定制开发需突破硬件交互与软件矩阵的技术壁垒。核心…

缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级

1. 缓存雪崩&#xff08;Cache Avalanche&#xff09;定义&#xff1a;缓存雪崩是指大量缓存中的数据在同一时间过期&#xff0c;导致大量请求同时访问数据库&#xff0c;造成数据库压力骤增&#xff0c;甚至可能导致数据库崩溃。原因&#xff1a;多个缓存的 key 在同一时间过期…