栈的基础概念与经典题目(Leetcode题解-Python语言)

栈是先入后出后入先出)的数据结构,常用操作就 push 和 pop,Python中用列表实现即可,基本概念可以看Leetbook相关章节。

普通栈

232. 用栈实现队列

class MyQueue:def __init__(self):self.stack1 = []self.stack2 = []self.size = 0def push(self, x: int) -> None:while self.stack2:self.stack1.append(self.stack2.pop())self.stack1.append(x)self.size += 1def pop(self) -> int:while self.stack1:self.stack2.append(self.stack1.pop())self.size -= 1ans = self.stack2.pop()while self.stack2:self.stack1.append(self.stack2.pop())return ansdef peek(self) -> int:return self.stack1[0]def empty(self) -> bool:return self.size == 0

两个栈,用 stack1 来存放 push 进来的数,当要 pop 的时候,借助 stack2 把最左边的数 pop 出去(相当于 popleft),然后再把剩余的数放回 stack1,由于需要判断空,所以用一个 size 大小来记录。

155. 最小栈(剑指 Offer 30. 包含min函数的栈)

class MinStack:def __init__(self):self.stack = [(0, float('+inf'))]def push(self, x: int) -> None:self.stack.append((x, min(self.stack[-1][1], x)))def pop(self) -> None:self.stack.pop()def top(self) -> int:return self.stack[-1][0]def getMin(self) -> int:return self.stack[-1][1]

实现最小栈的关键就是要用辅助栈记录每次 push 操作时的最小值,这样栈值在递增时,最小值永远是第一个值(如 [1, 2, 3, 4] 对应 [1, 1, 1, 1]);在递减时,最小值永远是当前值(如 [4, 3, 2, 1] 对应 [4, 3, 2, 1])。

1047. 删除字符串中的所有相邻重复项

class Solution:def removeDuplicates(self, s: str) -> str:stack = []for ch in s:if stack and stack[-1] == ch:stack.pop()else:stack.append(ch)return ''.join(stack)

栈的最重要的应用就是匹配,这是由它后入先出的性质所决定的。

20. 有效的括号

class Solution:def isValid(self, s: str) -> bool:if len(s) % 2 == 1:return Falsestack = []for ch in s:if ch in ('(', '[', '{'):stack.append(ch)else:if len(stack) == 0:return Falsepre = stack.pop()if (pre == '(' and ch != ')') or (pre == '[' and ch != ']') or (pre == '{' and ch != '}'):return Falsereturn len(stack) == 0

首先判断长度,若为奇数必然不能匹配,直接返回 False。然后分类讨论:如果是三个左括号之一,就 push 进入栈;如果是三个右括号之一,就检查栈顶,若栈顶为空就肯定不匹配,不为空则考察弹出的栈顶元素,若不是对应的左括号则返回 False。最后如果还有左括号(栈非空),也返回 False。

227. 基本计算器 II

class Solution:def calculate(self, s: str) -> int:stack = []size = len(s)index = 0op = '+'while index < size:if s[index] == ' ':index += 1continueif s[index] in '+-*/':op = s[index]elif s[index].isdigit():num = ord(s[index]) - ord('0')while index + 1 < size and s[index+1].isdigit():index += 1num = num * 10 + ord(s[index]) - ord('0')if op == '+':stack.append(num)elif op == '-':stack.append(-num)                    elif op == '*':top = stack.pop()stack.append(top * num)elif op == '/':top = stack.pop()stack.append(int(top / num))index += 1return sum(stack)

这题与上一个的括号题类似,也是分类讨论。如果遇到空格则跳过;如果遇到符号则记录下来;如果遇到数字,则根据其前面的符号来进行相应的运算。这里用 while 循环是因为要处理多位数字的情况,如 42 这种数,在遇到符号前都将其作为一个数(而不是 4 和 2 两个数)。

150. 逆波兰表达式求值

class Solution:def evalRPN(self, tokens: List[str]) -> int:stack = []size = len(tokens)index = 0while index < size:if tokens[index] in '+-*/':second = stack.pop()first = stack.pop()if tokens[index] == '+':num = first + secondelif tokens[index] == '-':num = first - secondelif tokens[index] == '*':num = first * secondelif tokens[index] == '/':num = int(first / second)stack.append(num)index += 1else:stack.append(int(tokens[index]))index += 1return stack.pop()

仿照上一题的写法,同样是分类讨论,字符是数字的话就入栈,是运算符的话就让两个操作数出栈,进行运算后把结果再入栈。由于这题多位数是直接给出来了的,所以可以用 for 循环而不是 while 循环,如下所示:

class Solution:def evalRPN(self, tokens: List[str]) -> int:stack = []for token in tokens:if token == '+':stack.append(stack.pop() + stack.pop())elif token == '-':stack.append(-stack.pop() + stack.pop())elif token == '*':stack.append(stack.pop() * stack.pop())elif token == '/':stack.append(int(1/stack.pop()*stack.pop()))else:stack.append(int(token))return stack.pop()

946. 验证栈序列(剑指 Offer 31. 栈的压入、弹出序列)

class Solution:def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:pop_pointer = 0stack = []for num in pushed:stack.append(num)while stack and pop_pointer < len(popped) and stack[-1] == popped[pop_pointer]:stack.pop()pop_pointer += 1return pop_pointer == len(popped)

用指针记录 popped 序列,然后逐个把 pushed 序列的元素 push 进入栈中,如果出现相同值,则弹出栈顶元素,同时指针右移1位,如果所有元素都能pop 则返回 True。

单调栈

496. 下一个更大元素 I

class Solution:def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:ans = []stack = []num_map = dict()for num in nums2:while stack and stack[-1] < num:num_map[stack[-1]] = numstack.pop()stack.append(num)for num in nums1:ans.append(num_map.get(num, -1))return ans

利用单调栈和字典记录下 nums2 中每个元素右边第一个比自己大的元素,然后遍历 nums1 从字典找相应答案即可。

503. 下一个更大元素 II

class Solution:def nextGreaterElements(self, nums: List[int]) -> List[int]:n = len(nums)ans = [-1 for _ in range(n)]stack = []for i in range(n * 2):while stack and nums[i % n] > nums[stack[-1]]:index = stack.pop()ans[index] = nums[i % n]stack.append(i % n)return ans

通过循环 2n 次可以达到循环数组的效果,但毕竟答案要的索引是 n 个,所以通过对 n 取余来表示原数组的下标。

739. 每日温度

class Solution:def dailyTemperatures(self, temperatures: List[int]) -> List[int]:n = len(temperatures)ans = [0 for _ in range(n)]stack = []for i in range(n):while stack and temperatures[stack[-1]] < temperatures[i]:index = stack.pop()ans[index] = i - indexstack.append(i)return ans

遍历每一天的温度,用一个栈记录每天的温度下标,当遍历到第 i 天时,比较第 i 天是否大于前面某天的温度,如果是则弹出该天(已找到答案),并在 ans 数组中记录下天数(差值)。

316. 去除重复字母(1081. 不同字符的最小子序列)

class Solution:def removeDuplicateLetters(self, s: str) -> str:stack = []counter = collections.Counter(s)for ch in s:if ch not in stack:while stack and ch < stack[-1] and counter[stack[-1]] > 0:stack.pop()stack.append(ch)counter[ch] -= 1return ''.join(stack)

首先用字典记录下每个字符出现的次数,然后从左往右遍历字符串。对于每一个字符,如果它已经在单调递减栈里面了,则不需要入栈,直接次数减 1;如果它不在栈里,则判断栈顶元素是否可以出栈(比当前字符大且不是剩下的唯一字符),之后再将字符入栈。

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

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

相关文章

ASP.NET Core 3.x启动时运行异步任务(二)

这一篇是接着前一篇在写的。如果没有看过前一篇文章&#xff0c;建议先去看一下前一篇&#xff0c;这儿是传送门一、前言前一篇文章&#xff0c;我们从应用启动时异步运行任务开始&#xff0c;说到了必要性&#xff0c;也说到了几种解决方法&#xff0c;及各自的优缺点。最后&a…

leetcode583. 两个字符串的删除操作

一:题目 二:上码 class Solution { public:/**思路:题目给的是让求最值,那么首先就会想到的是动态规划,我们想得到答案的结果其实有多个的&#xff0c;但是我们是取最小的步数动态规划 五步走:1>:确定dp数组以及下标的含义dp[i][j]表示的是 以下标i-1结尾的字符串word1,和…

C# 中居然也有切片语法糖,太厉害了

一&#xff1a;背景 1. 讲故事昨天在 github 上准备找找 C# 9 又有哪些新语法糖可以试用&#xff0c;不觉在一个文档上看到一个很奇怪的写法: foreach (var item in myArray[0..5]) 哈哈&#xff0c;熟悉又陌生&#xff0c;玩过python的朋友对这个 [0..5] 太熟悉不过了&#x…

子串、子数组与子序列类型问题的动态规划求解(Leetcode题解-Python语言)

一般来说&#xff0c;子串和子数组都是连续的&#xff0c;而子序列是可以不连续的&#xff0c;遇到子序列问题基本上都是用动态规划求解。 53. 最大子数组和&#xff08;剑指 Offer 42. 连续子数组的最大和&#xff09; class Solution:def maxSubArray(self, nums: List[int…

跟我一起学.NetCore之中间件(Middleware)简介和解析请求管道构建

前言中间件(Middleware)对于Asp.NetCore项目来说&#xff0c;不能说重要&#xff0c;而是不能缺少&#xff0c;因为Asp.NetCore的请求管道就是通过一系列的中间件组成的&#xff1b;在服务器接收到请求之后&#xff0c;请求会经过请求管道进行相关的过滤或处理&#xff1b;正文…

leetcode647. 回文子串

一&#xff1a;题目 二&#xff1a;上码 class Solution { public:/**思路:动态规划五步走1>:确定dp数组以及下标的含义dp[i][j] 表示的是在[i,j]范围内的字串 是否是 回文子串&#xff0c;如果是的话那么dp[i][j] true2>确定dp数组的状态转移方程那么就有两种情况 s[i…

Leetcode周赛复盘——第 276 场力扣周赛

第一次参加周赛&#xff0c;AC了三道题&#xff0c;也算不错的成绩了&#xff0c;从现在开始每周的周赛我都会参加并且复盘&#xff0c;有兴趣的小伙伴可以一起讨论。 5980. 将字符串拆分为若干长度为 k 的组 class Solution:def divideString(self, s: str, k: int, fill: s…

leetcode516. 最长回文子序列

一:题目 二:上码 class Solution { public:/**思路:1.分析题意 这个是让我们求最值,那么首先想到动态规划2.动态规划1>:确定dp数组以及下标的含义dp[i][j] 表示字符串在[i,j]范围内的最长回文子序列2>:确定dp数组的状态递推公式那么就是s[i] 与 s[j] 相等 不相等两种情况…

Leetcode周赛复盘——第 278 场力扣周赛

5993. 将找到的值乘以 2 我的做法是将数组从小到大排序之后&#xff0c;再将找到的值乘以2&#xff1a; class Solution:def findFinalValue(self, nums: List[int], original: int) -> int:nums.sort()for num in nums:if original num:original * 2return original然而…

C#刷剑指Offer | 二叉搜索树的后序遍历序列

【C#刷题】| 作者 / Edison Zhou这是EdisonTalk的第289篇原创内容我们来用之前学到的数据结构知识来刷《剑指Offer》的一些核心题目&#xff08;精选了其中30道题目&#xff09;&#xff0c;希望对你有帮助&#xff01;本文题目为&#xff1a;二叉搜索树的后序遍历序列。1题目介…

leetcode739. 每日温度

一:题目 二:上码 // class Solution { // public: // vector<int> dailyTemperatures(vector<int>& temperatures) { // vector<int> ans(temperatures.size(),0);// for (int i 0; i < temperatures.size(); i) {// …

Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛

双周赛&#xff1a; 5984. 拆分数位后四位数字的最小和 class Solution:def minimumSum(self, num: int) -> int:a, b, c, d sorted(list(map(int, str(num))))return 10 * (a b) c dstr(num)得到字符串序列&#xff0c;然后用map函数对序列的每个字符转换为数字&…

使用SWAGGER和ASP.NET CORE设置可选路由参数

使用SWAGGER和ASP.NET CORE设置可选路由参数根据OpenAPI 3.0&#xff0c;这是不可能的。但是&#xff0c;如果您真的希望成为现实呢&#xff1f;您是否必须解决并允许您的Swagger文档出错&#xff1f;我在这里向您展示如何使用Swagger和ASP.NET Core设置可选的路由参数。等等&a…

在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)

在一维数组中的考察中&#xff0c;最常见的就是找出数组中的重复数、只出现一次的数或者丢失&#xff08;消失&#xff09;数等等。 一般来说&#xff0c;首先想到的就是用哈希表&#xff08;集合&#xff09;来记录出现过的数&#xff0c;基本所有的题都可以用集合来做&#…

Confluent官博:Kafka最牛队列,性能15倍于RabbitMQ!

“容器、Kubernetes、DevOps、微服务、云原生&#xff0c;这些技术名词的频繁出现&#xff0c;预兆着新的互联网技术时代的到来&#xff0c;大数据高并发将不再遥远&#xff0c;而是大部分项目都必须面对的&#xff0c;消息队列则是核心利器&#xff01;成熟的消息队列产品很多…

leetcode503. 下一个更大元素 II

一:题目 二:上码 class Solution { public:/**思路: 1.将两个nums拼接到一块这里拼接到一块,当我们最后的元素找不到比其大的时候 就会开始从头开始这样的话就可以继续进行 入栈 或者出栈的操作入栈就是比我栈顶小的元素&#xff0c;出栈的话 那就是 找到了比其大的元素了…

队列的基础概念与经典题目(Leetcode题解-Python语言)

队列是先入先出&#xff08;后入后出&#xff09;的数据结构&#xff0c;常用操作就 push 和 popleft&#xff0c;Python中用列表中的 pop(0) 或者 collection.deque的 popleft() 都可以。 普通队列 225. 用队列实现栈 class MyStack:def __init__(self):self.queue1 []sel…

跟我一起学.NetCore之中间件(Middleware)应用和自定义

前言Asp.NetCore中的请求管道是通过一系列的中间件组成的&#xff0c;使得请求会根据需求进行对应的过滤和加工处理。在平时开发中会时常引用别人定义好的中间件&#xff0c;只需简单进行app.Usexxx就能完成中间件的注册&#xff0c;但是对于一些定制化需求还得自己进行处理和封…

leetcode42. 接雨水

一:题目 二:上码 // class Solution { // public: // /**超时 // 思路: // 1.我们按列来计算 这就是表明的是 我们求取接雨水 向上的高度就是雨水量 // 但是这里的话我们的需要对雨水的高度 来进行判定 // 2.那么如何判定…

贪心的问题合集(Leetcode题解-Python语言)

贪心算法&#xff08;Greedy Algorithm&#xff09;&#xff1a;是一种在每次决策时采用当前状态下最优或最好的策略&#xff0c;从而希望导致结果是最好或最优的算法。 455. 分发饼干 class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:…