终于来到了栈专题,想想之前来阿里的时候就是面试了一道栈最终通过了终面,也是十分怀念了。

739. Daily Temperatures[Medium]

思路:这就是最典型的单调栈问题了。从后向前维护下一个更大值或者下一个更大值的位置。

可以看一下当年面阿里时的博客,一切都还记忆犹新

单调栈专题练--下一个更大元素-CSDN博客

至于栈的数据结构,先尝试了使用java自身的数据结构Stack,但确实慢的让人发指,可能其内部各种并行安全机制拖慢了其本身的性能

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperatures(int[] temperatures) {int len = temperatures.length;Deque<Integer> stack = new ArrayDeque<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {stack.pop();}if (!stack.isEmpty()) {result[i] = stack.peek() - i;}stack.push(i);}return result;}
}

多想一下:用链表实现栈

再尝试用链表LinkedList来实现栈,速度要快了很多 

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesWithLinkedList(int[] temperatures) {int len = temperatures.length;List<Integer> stack = new LinkedList<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.get(stack.size() - 1)]) {stack.remove(stack.size() - 1);}if (!stack.isEmpty()) {result[i] = stack.get(stack.size() - 1) - i;}stack.add(i);}return result;}
}

多想一下:用双端队列来实现栈

Qwen了一下,ai推荐用ArrayDeque,那么来试试,确实比链表还要快一些

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesWithDeque(int[] temperatures) {int len = temperatures.length;Deque<Integer> stack = new ArrayDeque<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {stack.pop();}if (!stack.isEmpty()) {result[i] = stack.peek() - i;}stack.push(i);}return result;}
}

多想一下:用原始数组手动实现

一切花里胡哨都不如自己手撕,还是手撕大法好呀

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesManual(int[] temperatures) {int len = temperatures.length;int[] stack = new int[len];int top = -1;int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (top>=0 && temperatures[i] >= temperatures[stack[top]]) {top--;}if (top>=0) {result[i] = stack[top] - i;}stack[++top]=i;}return result;}
}

 

155. Min Stack[Medium]

思路:要求设计一个最小栈,不仅要能进行原有栈操作的基础上,还要能常数复杂度内求出当前栈的最小值。


/*** Author Owen_Q** a stack that supports push, pop, top, and retrieving the minimum element in constant time.* <p>* Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();**/
public interface MinStack {/*** pushes the element val onto the stack.** @param val the element to be pushed*/void push(int val);/*** removes the element on the top of the stack.*/public void pop();/*** gets the top element of the stack.** @return the top element of the stack*/public int top();/*** retrieves the minimum element in the stack.** @return the minimum element in the stack*/public int getMin();
}

其实考虑动态变更的数据结构实时求最小值,首先想到的就是优先队列或者堆。但这题需要常数复杂度,那么多思考一下。由于栈的特点是先进后出,即栈底元素一定比上方元素存在的时间长。换句话说,如果某个元素在入栈的那一刻没有成为最小值,那么其将永远没有机会再成为最小值了。因为其下方将永远存在比其小的元素。那么其实我们只需要一个辅助栈,来记录一下当前栈内最小元素,和原栈元素同步更新。当入栈元素比栈内最小元素小时,则更新栈内最小元素,否则栈内最小元素维持原值。

/*
Author Owen_Q
*/
public class MinStackDeque implements MinStack {Deque<Integer> stack;Deque<Integer> minStack;public MinStackDeque() {stack = new ArrayDeque<>();minStack = new ArrayDeque<>();}@Overridepublic void push(int val) {stack.push(val);if (minStack.isEmpty() || val <= minStack.peek()) {minStack.push(val);} else {minStack.push(minStack.peek());}}@Overridepublic void pop() {if (stack.isEmpty()) {throw new RuntimeException("stack is empty");}stack.pop();minStack.pop();}@Overridepublic int top() {if (stack.isEmpty()) {throw new RuntimeException("stack is empty");}return stack.peek();}@Overridepublic int getMin() {if (minStack.isEmpty()) {throw new RuntimeException("stack is empty");}return minStack.peek();}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

多想一下:用链表模拟栈

想着优化一下,但是由于数组的大小未知,因此不能直接手撕,想到可以尝试手动模拟链表来实现栈。恰巧,不难发现,其实上面使用的两个栈完全是一模一样的,因此完全可以把栈最小值当成链表节点的一部分,说干就干

/*
Author Owen_Q
*/
public class MinStackNodes implements MinStack {private static class StackNode {int val;int minVal;StackNode next;public StackNode(int val, int minVal, StackNode next) {this.val = val;this.minVal = minVal;this.next = next;}}StackNode stack;public MinStackNodes() {stack = null;}@Overridepublic void push(int val) {if (stack == null) {stack = new StackNode(val, val, null);} else {stack = new StackNode(val, Math.min(val, stack.minVal), stack);}}@Overridepublic void pop() {if (stack == null) {throw new RuntimeException("stack is empty");}stack = stack.next;}@Overridepublic int top() {if (stack == null) {throw new RuntimeException("stack is empty");}return stack.val;}@Overridepublic int getMin() {if (stack == null) {throw new RuntimeException("stack is empty");}return stack.minVal;}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

效果拔群

20. Valid Parentheses[Easy]

思路:括号验证,括号问题其实很容易想到栈,直接用栈模拟一下即可。最后特判一下如果串长是奇数那么直接返回失败即可

/*
Author Owen_Q
*/
public class ParenthesesValidator {public static boolean isValid(String s) {int len = s.length();char[] stack = new char[len];int top = 0;if ((len & 1) == 1) {return false;}for (int i = 0; i < len; i++) {char c = s.charAt(i);if (c == '(') {stack[top++] = ')';} else if (c == '[') {stack[top++] = ']';} else if (c == '{') {stack[top++] = '}';} else {if (top == 0 || stack[--top] != c) {return false;}}}return top == 0;}
}

394. Decode String[Medium]

思路:一般存在递归嵌套的结构都首先想到栈,这里栈需要维护两个值,一个是前序字母序列,还有一个就是需要重复的次数。然后用一个变量实时维护当前字符串,另一个变量将重复次数从字符串转换为数字。于是操作就变得很清晰了,如果遇到字母或者数字,就维护两个特定的变量。每次遇到左括号时,将维护的字符串和重复次数加入栈内,并将两个变量清空。每次遇到右括号时,则将栈顶元素出栈,获得前序字母序列和重复次数。于是将当前维护的字符串变量重复特定次数后加上前序字母序列,组成新的字符串再维护到当前变量中。

/*
Author Owen_Q
*/
public class StringDecoder {private static class DecoderNode {int count;StringBuffer str;DecoderNode next;public DecoderNode(int count, StringBuffer str, DecoderNode next) {this.count = count;this.str = str;this.next = next;}}public static String decodeString(String s) {int len = s.length();StringBuffer st = new StringBuffer();int cnt = 0;DecoderNode stack = null;for (int i = 0; i < len; i++) {char c = s.charAt(i);if (c <= '9' && c >= '0') {cnt = cnt * 10 + c - '0';} else if (c == '[') {stack = new DecoderNode(cnt, st, stack);st = new StringBuffer();cnt = 0;} else if (c == ']') {if (stack == null) {throw new RuntimeException("stack is empty");}int stackCount = stack.count;for (int j = 0; j < stackCount; j++) {stack.str.append(st);}st = stack.str;stack = stack.next;} else {st.append(c);}}return st.toString();}
}

用链表维护栈是真的好用,效率直接拉满

多想一下:转栈为DFS

有句话叫dfs问题都可以转化为栈问题,那么这题其实就是典型的dfs转化而来的栈,那么复原用dfs实现一下试试

/*
Author Owen_Q
*/
public class StringDecoder {public static String decodeStringWithDfs(String s) {return dfs(s, 0).getValue().toString();}private static Pair<Integer, StringBuffer> dfs(String s, int pos) {StringBuffer st = new StringBuffer();int cnt = 0;int len = s.length();while (pos < len) {char c = s.charAt(pos);if (c <= '9' && c >= '0') {cnt = cnt * 10 + c - '0';} else if (c == '[') {Pair<Integer, StringBuffer> pair = dfs(s, pos + 1);StringBuffer stackStr = pair.getValue();for (int j = 0; j < cnt; j++) {st.append(stackStr);}cnt = 0;pos = pair.getKey();} else if (c == ']') {return new Pair<>(pos, st);} else {st.append(c);}pos++;}return new Pair<>(cnt, st);}
}

 84. Largest Rectangle in Histogram[Hard]

思路:求直方图的最大矩形区域,这个和当年阿里面试题简直有异曲同工之妙。最大01子矩阵问题(单调栈优化)_01最大子矩阵-CSDN博客

在原有单调栈求下一个最小值(最大值的变种)基础上,要分别求元素的前后方的最小值。

再回忆一下单调栈。针对每个位置,会将栈中所有更大的数全都出站,那么此时栈定元素就是下一个更小的数。接下来要求上一个更小的数。我们再继续思考出入栈的过程,刚刚说到,此时将当前数入栈,那么当前数再次出栈的时候栈顶元素一定还是下一个更小的数。而恰巧,当前数出栈的时候,就说明了上一个更小的数出现了,因为只有更小的数才能驱使栈内元素出栈。总结而言,当栈内元素出栈时,当前元素是出栈元素的上一个更小元素,出栈后的栈顶元素是出栈元素的下一个更小的元素。

再总结一下,针对单调栈,如果只需要求下一个更小元素,可以在枚举位置处获取到。但如果想知道上一个更小元素,则需要等到元素出栈后才能获取到

/*
Author Owen_Q
*/
public class LargestHistogramRectangle {public static int largestRectangleArea(int[] heights) {int len = heights.length;int[] stack = new int[len];int top = -1;int result = 0;for (int i = len - 1; i >= 0; i--) {while (top >= 0 && heights[i] <= heights[stack[top]]) {int now = heights[stack[top]];top--;int width = top == -1 ? len - i - 1 : stack[top] - i - 1;result = Math.max(result, width * now);}stack[++top] = i;}while (top >= 0) {int now = heights[stack[top]];top--;int width = top == -1 ? len : stack[top];result = Math.max(result, width * now);}return result;}
}

完美

完结撒花

 

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

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

相关文章

PIXHAWK(ardupilot4.52)NMEA的解析bug

最近在测试过程中发现在椭球高为负的地方&#xff0c;地面站读取GPS_RAW_INT (24)消息中的alt高度竟然是正值。而消息中定义的alt并不是一个unsigned数据&#xff0c;理论上是带有正负符号的。 查看gga的原始信息&#xff1a; $GPGGA,063718.40,3714.8533856,N,11845.9411766,…

Linux容器讲解以及对应软件使用

一、容器基础知识讲解 1.1 微服务的部署策略 部署单体应用意味着运行大型应用的多个相同副本&#xff0c;通常提供若干台&#xff08;N&#xff09;服务器&#xff08;物理机或虚拟 机&#xff09;&#xff0c;在每台服务器上运行若干个&#xff08;M&#xff09;应用实例。部…

企业级应用技术-ELK日志分析系统

目录 #1.1ELK平台介绍 1.1.1ELK概述 1.1.2Elasticsearch 1.1.3Logstash 1.1.4Kibana #2.1部署ES群集 2.1.1基本配置 2.1.2安装Elasticsearch 2.1.3安装Logstash 2.1.4Filebeat 2.1.5安装Kibana 1.1ELK平台介绍 1.1.1ELK概述 ELK 是三个开源工具的缩写&#xff0c;分别是Elas…

Shiro漏洞复现

Shiro简介 Apache Shiro是一种功能强大且易于使用的Java安全框架&#xff0c;它执行身份验证、授权、 加密和会话管理&#xff0c;可用于保护任何应用程序的安全。 Shiro提供了应用程序安全性API来执行以下方面&#xff1a; 1.身份验证&#xff1a;证明用户身份&#xff0c;通…

VSCode 中使用 Google Test(GTest)框架测试

VSCode 中使用 Google Test&#xff08;GTest&#xff09;框架在 VSCode 中对 C 代码进行测试的示例&#xff1a; 一、Unbutu x86使用gtest 环境配置 安装 GTest &#xff1a;在 Ubuntu 系统中&#xff0c;可以通过命令sudo apt-get install libgtest-dev安装 GTest 库。对于…

【1.6 漫画数据库设计实战 - 从零开始设计高性能数据库】

1.6 漫画数据库设计实战 - 从零开始设计高性能数据库 &#x1f3af; 学习目标 掌握数据库表结构设计原则理解字段类型选择与优化学会雪花算法ID生成策略掌握索引设计与优化技巧了解分库分表设计方案 &#x1f4d6; 故事开始 小明: “老王&#xff0c;我总是不知道怎么设计数…

OSPF虚拟链路术语一览:快速掌握网络路由

大家好&#xff0c;这里是G-LAB IT实验室。今天带大家了解一下OSPF的相关知识&#xff01; 01 OSPF虚拟链路术语大全 网络架构中&#xff0c;OSPF&#xff08;开放式最短路径优先&#xff09;是一种重要的路由协议。通过其链路状态路由机制&#xff0c;OSPF能够有效维护和更新…

oracle常用的函数(一) 之 to_char、to_date

文章目录 前言to_char基本语法格式模型格式模型介绍无FM示例使用FM输出货币负数输出尖括号 将日期格式化将数字格式化为带有货币符号和千位分隔符的格式总结 to_date语法语法示例 戳这里&#xff0c;第二弹 → oracle常用的函数&#xff08;二&#xff09; 之 nvl、decode、l…

数据库服务器宕机的处理方法与实战策略

在当今数字化时代,数据库作为企业数据存储与管理的核心,承载着业务运行的关键信息。一旦数据库服务器宕机,将导致业务中断、数据丢失等严重后果,甚至可能给企业带来巨大的经济损失和声誉损害。因此,掌握一套系统、科学的数据库服务器宕机处理方法尤为重要。本文将从应急响…

如何hack边缘的kubelet修改Cgroup数值

之前做了一个VPA项目的需求&#xff0c;就是需要不重启的方式修改容器的Cgroup的值已达到垂直扩缩容的目的&#xff0c;项目中核心的思路如下 上游下发要VPA的结果的值写入到容器的Annotation里面Kubelet 感知到这个 annoation 的变化我们本地运行一个 Agent&#xff0c;里面运…

熟悉 PyCharm

界面 我们常用的就这个几个地方&#xff1a; 常用配置 调整字体大小 Ctrl 滚轮调整字体大小 插件推荐 Indent Rainbow 该插件的作用在于能够对于不同层级缩进的空格标注不同的颜色&#xff1a; 快捷键 快捷键的 pdf 下载链接&#xff1a; Windows 版&#xff1a;https:…

pytorch--模型训练的一般流程

文章目录 前言0、数据集准备1、数据集2、dataset3、model4、训练模型 前言 在pytorch中模型训练一般分为以下几个步骤&#xff1a; 0、数据集准备 1、数据集读取&#xff08;dataset模块&#xff09; 2、数据集转换为tensor&#xff08;dataloader模块&#xff09; 3、定义模型…

智能合同管理实战:基于区块链的电子签约技术实现

在数字经济时代,传统纸质合同签署方式已难以满足企业高效、安全、合规的业务需求。智能合同管理(Smart Contract Management)结合区块链技术,正在重塑电子签约流程,实现合同全生命周期的自动化、可追溯和防篡改。本文将深入探讨基于区块链的电子签约技术实现,涵盖核心架构…

设计模式精讲 Day 22:模板方法模式(Template Method Pattern)

【设计模式精讲 Day 22】模板方法模式&#xff08;Template Method Pattern&#xff09; 文章标签 设计模式, 模板方法模式, Java开发, 面向对象设计, 软件架构, 设计模式实战, Java应用开发 文章简述 模板方法模式是一种行为型设计模式&#xff0c;它通过定义一个算法的骨架…

如何在pytorch中使用tqdm:优雅实现训练进度监控

文章目录 为什么需要进度条&#xff1f;tqdm 简介基础用法示例深度学习中的实战应用1. 数据加载进度监控2. 训练循环增强版3. 验证阶段集成 高级技巧与最佳实践1. 自定义进度条样式2. 嵌套进度条&#xff08;多任务&#xff09;3. 分布式训练支持4. 与日志系统集成 性能优化建议…

Linux中的xxd命令详解

xxd 是一个 十六进制转储&#xff08;hex dump&#xff09;工具&#xff0c;通常用于将二进制文件转换为十六进制格式&#xff0c;或者反向转换&#xff08;十六进制→二进制&#xff09;。它是 vim 的一部分&#xff0c;但在大多数 Linux 系统&#xff08;如 Ubuntu&#xff0…

磐维数据库panweidb3.1.0单节点多实例安装

0 说明 业务科室提单需要在某台主机上部署多个单机磐维数据库&#xff0c;用于业务测试。以下内容展示如何在单节点安装多个磐维数据库实例。 1 部署环境准备 1.1 IP 地址及端口 instipport实例1192.168.131.1717700实例2192.168.131.1727700 在131.17上分别安装两个实例&…

转录组分析流程(三):功能富集分析

我们的教程主要是以一个具体的例子作为线索,通过对公共数据库数据bulk-RNA-seq的挖掘,利用生物信息学分析来探索目标基因集作为某种疾病数据预后基因的潜能及其潜在分子机制,同时在单细胞水平分析(对scRNA-seq进行挖掘)预后基因的表达,了解细胞之间的通讯网络,以期为该疾病…

全面掌握 tkinter:Python GUI 编程的入门与实战指南

在自动化、工具开发、数据可视化等领域&#xff0c;图形用户界面&#xff08;GUI&#xff09;往往是提升用户体验的重要方式。作为 Python 官方内置的 GUI 库&#xff0c;tkinter 以其轻量、跨平台、易于学习的特性成为初学者和轻量级应用开发者首选。 本文将以深入浅出的方式…

TDH社区开发版安装教程

&#xff08;注&#xff1a;本文章来源于星环官网安装手册&#xff09; 后面放置了视频和安装手册连接 1、硬件及环境要求 Docker17及以上版本&#xff0c;支持Centos&#xff0c;Ubuntu等系统&#xff08;注&#xff1a;这里我使用CentOS-7版本&#xff0c;最佳版本推荐为7.…