Leetcode之栈和队列

本文详细介绍了栈和队列这两种数据结构及其在编程中的应用,包括有效括号检查、简化路径、字符串解码和基本计算器问题的解决方案。通过实例展示了栈和队列如何解决递归和逻辑运算问题,强调了单调栈在处理单调序列中的作用,如每日温度计算和最大矩形面积查找。同时,文章还探讨了如何利用栈和队列优化算法的时间复杂度,确保高效运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

栈和队列是操作受限的线性结构

栈:先进后出,压栈和出栈的时间复杂度为O(1)

队列:
队尾进入,队首出去。先进先出,出队和入队的时间复杂度为O(1)
collections.deque() deque是指双端队列,队首和队尾均可入队和出队

20.有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

思路:
为了实现匹配的操作,当检测到输入的符号为 (,[,{时,向栈中压入),],}。

当输入一个字符不为上述符号时,如果栈是空的,或者栈顶元素和它不相等,返回false。
这里注意的是,运用了逻辑短路,如果stack已经是空的了,就不会执行i!=stack.pop(),防止空数组无法执行pop而报错。
此外,stack.pop()放入语句中执行时,都会弹出最外面的元素。

class Solution:
    def isValid(self, s: str) -> bool:
        if not s:return True
        stack = []
        for i in s:
            if i == '(':
                stack.append(')')
            elif i == '[':
                stack.append(']')
            elif i == '{':
                stack.append('}')
            elif not stack or i!=stack.pop():
                return False
        
        if not stack:
            return True
        else:
            return False

71.简化路径
在这里插入图片描述
在这里插入图片描述

思路:
(1)首先,将输入的字符串看作一个数组,把每个符号拆分开来,就能看出问题的本质是解决当遇到’.’、’…’、以及’ '时应当如何处理这个问题。

(2)遇到这种问题时,首先应该将path按照’/'分割开,得到每个单独的字符。代码为:

path = path.split('/')

(3)其次,遍历分割好的字符串,如果该字符是空,或者’.‘时,不要管他(continue)
如果是’…’,但queue是空的时候,不管他(continue)
如果queue不空,则弹出栈顶的字符,因为要返回上一级。
以上情况均不符合时,入栈。

(4)到了输出的环节,注意输出的语句:

res = res+'/'
res = res + queue.popleft()

其中,为什么使用deque,是因为如果使用栈的话,弹出的不是最根的路径。应该弹出栈中先进入的元素,只有deque才能做得到。

class Solution:
    def simplifyPath(self, path: str) -> str:
        queue = collections.deque()
        path = path.split('/')
        for i in path:
            if not i or i == '.':
                continue
            elif i == '..' and not queue:
                continue
            elif i == '..' and queue:
                queue.pop()
            else:
                queue.append(i)
        
        res = ''
        if not queue:
            return '/'
        while(queue):
            res = res+'/'
            res = res + queue.popleft()
        return res

394.字符串解码
在这里插入图片描述

该题主要难度在于处理像 3[a2[c]]这样的循环结构。
numstack用于存储循环多少次的栈
strstack用于存储循环部分的栈

(1)
num = num*10+int©是将多个单独字符串数字转换成一整个数字的常用方法。
(2)当c==’[‘时,将数字num压入栈,字符res压入栈(字符res代表一整个字符,从后面的res += c可以看出)。清空res和num
(3)当c==’]'时,将res转化为num个res,具体做法见程序,其中,因为item已经包括了一个res,所以循环结构是从1开始的。

class Solution:
    def decodeString(self, s: str) -> str:
        num = 0
        res = ''
        numstack = []
        strstack = []
        for c in s:
            if c >= '0' and c <= '9':
                num = num*10+int(c)
            elif c == '[':
                numstack.append(num)
                strstack.append(res)
                res = ''
                num = 0
            elif c == ']':
                item = res
                for i in range(1,numstack.pop()):
                    res += item
                res = strstack.pop() + res
            else:
                res += c
        return res

224.基本计算器
在这里插入图片描述

遇到这种情况,都需要把字符串看作中的每个字符单独地一个一个去处理。

class Solution:
    def calculate(self, s: str) -> int:
        presign = 1
        num = 0
        res = 0
        resstack = []
        signstack = []
        for c in s:
            if c >= '0' and c <='9':
                num = num*10+int(c)

            elif c == '+':
                res += presign*num
                presign = 1
                num = 0
            
            elif c == '-':
                res += presign*num
                presign = -1
                num = 0

            elif c == '(':
                resstack.append(res)
                signstack.append(presign)

                presign = 1
                res = 0

            elif c == ')':
                res += presign*num
                res *= signstack.pop()
                res += resstack.pop()
                num = 0
        return res + presign*num
class Solution:
    def calculate(self, s: str) -> int:
        presign = 1
        num = 0
        res = 0
        resstack = []
        signstack = []
        for c in s:
            if c >= '0' and c <='9':
                num = num*10+int(c)

            elif c == '+':
                res += presign*num
                presign = 1
                num = 0
            
            elif c == '-':
                res += presign*num
                presign = -1
                num = 0

            elif c == '(':
                resstack.append(res)
                signstack.append(presign)

                presign = 1
                res = 0

            elif c == ')':
                res += presign*num
                res *= signstack.pop()
                res += resstack.pop()
                num = 0
        return res + presign*num

227.基本计算器二

class Solution:
    def calculate(self, s: str) -> int:
        n = len(s)
        stack = []
        preSign = '+'
        num = 0
        for i in range(n):
            if s[i] != ' ' and s[i].isdigit():
                num = num * 10 + ord(s[i]) - ord('0')
            if i == n - 1 or s[i] in '+-*/':
                if preSign == '+':
                    stack.append(num)
                elif preSign == '-':
                    stack.append(-num)
                elif preSign == '*':
                    stack.append(stack.pop() * num)
                else:
                    stack.append(int(stack.pop() / num))
                preSign = s[i]
                num = 0
        return sum(stack)

946.验证栈序列

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        pushstack = []

        for i in range(len(pushed)):
            if pushed[i] != popped[0]:
                pushstack.append(pushed[i])
            elif pushed[i] == popped[0]:
                popped.pop(0)
            while pushstack and pushstack[-1] == popped[0]:
                pushstack.pop()
                popped.pop(0)
            
        
        if not popped:
            return True
        else:
            return False

单调栈:
要求栈中元素必须为升序元素排列或降序排列的。

739.每日温度
在这里插入图片描述

启发:
除了学习到一个解决单调递减栈的方法外,还要注意到在循环结构中,一定要有可以跳出循环的变量,这里的

prev = stack.pop()

我本来写成了prev= stack[-1],就跳不出来了。

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        if len(temperatures) == 1 :return 0

        stack = []
        res = [0]*len(temperatures)

        for i in range(len(temperatures)):
            x = temperatures[i]
            #单调递减栈
            while stack and x > temperatures[stack[-1]]:
                prev = stack.pop()
                res[prev] = i - prev
            stack.append(i)
            
        return res
            

739.每日温度

在这里插入图片描述

暴力求解

class Solution:
    def trap(self, height: List[int]) -> int:
        if len(height)<=2:
            return 0 
        n = len(height)

        leftMax = [0]*n
        leftMax[0] = height[0]
        for i in range(1,n):
            leftMax[i] = max(leftMax[i-1],height[i])
        
        rightMax = [0]*n
        rightMax[n-1] = height[n-1]
        for i in range(n-2,-1,-1):
            rightMax[i] = max(rightMax[i+1],height[i]) 

        ans = 0
        for i in range(1,len(height)-1):
            maxHeight = min(rightMax[i],leftMax[i])
            if maxHeight>height[i]:
                ans += maxHeight - height[i]
        return ans

由于上述两个数组leftMax和rightMax只用了一次,所以完全可以用两个数字来代替。所以我们采用双指针算法(对撞指针)。

class Solution:
    def trap(self, height: List[int]) -> int:
        if len(height)<=2:
            return 0 
        n = len(height)

        leftMax = 0
        rightMax = 0
        left = 0
        right = n-1
        ans = 0

        while left<right:
            leftMax = max(leftMax,height[left])
            rightMax = max(rightMax,height[right])
            if height[left] < height[right]:
                ans += leftMax - height[left]
                left += 1
            else:
                ans += rightMax - height[right]
                right = right - 1

        return ans

在这里插入图片描述
在这里插入图片描述
找到右边第一个,大于heigh[i]的才可以计算,否则就把heigh[i]压入栈中。

单调栈做法,看不太懂。

class Solution:
    def trap(self, height: List[int]) -> int:
        if len(height)<=2:
            return 0 
        n = len(height)
        ans = 0
        stack = []
        
        for i in range(n):
            while stack and height[i]>height[stack[-1]]:
                top = stack.pop()
                if not stack:
                    break
                
                leftIndex = stack[-1]
                currWidth = i -leftIndex -1
                currHeight = min(height[leftIndex],height[i])-height[top]
                ans += currWidth*currHeight
            stack.append(i)
        return ans

84.柱状图中的最大矩形
在这里插入图片描述

1)枚举宽
遍历每个矩阵,求出它们的面积
首先是得到矩阵的方法:
设立两个指针left和right
在left固定的情况下挑出比heights[left]小的heights[right],得到最小的高度(也是矩阵的高度),再乘宽度,和之前的ans做比较。

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:

        ans = 0

        for left in range(0,len(heights)):
            minHeight = heights[left]
            for right in range(left,len(heights)):
                minHeight = min(minHeight,heights[right])
                currWidth = right-left+1
                ans = max(ans,minHeight*currWidth)
        return ans

在这里插入图片描述

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:

        ans = 0
        
        for mid in range(0,len(heights)):
            height = heights[mid]

            left = mid
            right = mid

            while left>=0 and heights[left]>=height:left = left-1
            while right<=len(heights)-1 and heights[right]>=height:right = right +1

            ans = max(ans,height * (right-left-1))
            
        return ans

单调栈(一)

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:

        ans = 0
        left = [-1]*len(heights)
        right = [len(heights)]*len(heights)
        stack = []

        for i in range(len(heights)-1,-1,-1):
            while stack and heights[i]<heights[stack[-1]]:
                left[stack[-1]] = i
                stack.pop()
            stack.append(i)
		stack = []
        for j in range(0,len(heights)):
            while stack and heights[j]<heights[stack[-1]]:
                right[stack[-1]] = j
                stack.pop()
            stack.append(j)

        for mid in range(0,len(heights)):
            height = heights[mid]
            ans = max(ans,height * (right[mid]-left[mid]-1))

        return ans

单调栈(二)

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:

        ans = 0
        left = [-1]*len(heights)
        right = [len(heights)]*len(heights)
        stack = []

        for i in range(0,len(heights)):
            while stack and heights[i]<=heights[stack[-1]]:
                stack.pop()
            if not stack: left[i]=-1
            else:left[i] = stack[-1]
            stack.append(i)

        stack = []
        for j in range(len(heights)-1,-1,-1):
            while stack and heights[j]<=heights[stack[-1]]:
                stack.pop()
            if not stack: right[j]=len(heights)
            else:right[j] = stack[-1]
            stack.append(j)

        for mid in range(0,len(heights)):
            height = heights[mid]
            ans = max(ans,height * (right[mid]-left[mid]-1))

        return ans

单调栈(三)
一次遍历

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:

        ans = 0
        left = [-1]*len(heights)
        right = [len(heights)]*len(heights)
        stack = []

        for i in range(0,len(heights)):
            while stack and heights[i]<=heights[stack[-1]]:
                right[stack[-1]]= i 
                stack.pop()
            
            if not stack: left[i]=-1
            else:left[i] = stack[-1]
            stack.append(i)



        for mid in range(0,len(heights)):
            height = heights[mid]
            ans = max(ans,height * (right[mid]-left[mid]-1))

        return ans
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值