力扣算法个人总结 — 栈和队列

本文介绍了栈和队列的基本概念、Python实现以及它们在算法中的应用,如括号的有效性检测和最长有效括号问题。同时讨论了单调队列在滑动窗口问题中的解决方案。
摘要由CSDN通过智能技术生成

一、前言

因为栈和队列在平常代码中没有列表或者字符串等熟练,但是这类数据结构在力扣刷题中有不小的体量,所以这里对两者做一个总结,主要包括了结构的理解、常用的方法和一些经典的题目。这里同样也是第一版,后续有时间再慢慢完善。

二、栈和队列的概念

这里对于栈和队列的内容,主要是在【代码随想录:栈和队列】中进行学习,并按照自己的理解撰写。这里不对原理做详细介绍,想了解可以查看原文。

1、什么是栈
可以将栈和队列理解成一个只有一个出口的容器,同时,栈遵从数据的先进后出,而队列遵从数据的先进先出,他们都没办法通过索引直接获取容器中间的元素。
栈和队列的理解
在python中,对于两者的实现一般都可以用list完成。

# 栈的进出
stack = []
stack.append('a')
stack.pop()
# 队列的进出
stack.append('a')
stack.pop(0)

如果是为了追求更好的性能,python也提供了collections.deque()这个数据结构。deque是栈和队列的一种广义实现,是一种双向队列;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。

import collections
deque = collections.deque()
# deque的入栈和出栈
deque.append() # 只压入一个元素
deque.appendleft()
deque.expend() # 压入多个元素
deque.expendleft()
deque.pop()  # 弹出栈顶元素
deque.popleft()

二、常见例题

1、有效符号(一般是括号这种成对的符号)

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
3.每个右括号都有一个对应的相同类型的左括号。

这类题目的思路可以使用栈,原理是按照顺序将元素压入栈,如果左右符号匹配,则进行相关操作,否则继续。

法一:
def isValid(self, s: str) -> bool:
    stack = []
    for ch in s:
        if ch == '{':
            stack.append('}')
        elif ch == '[':
            stack.append(']')
        elif ch == '(':
            stack.append(')')
        elif not stack or stack[-1] != ch:
            return False
        else:
            stack.pop()
    return True if not stack else False
法二:
class Solution:
    def isValid(self, s: str) -> bool:
        dic = {'{': '}',  '[': ']', '(': ')', '?': '?'}
        stack = ['?']
        # 这里为了防止pop一个空的栈
        for c in s:
            if c in dic: stack.append(c)
            elif dic[stack.pop()] != c: return False 
        return len(stack) == 1
       

【32.最长有效括号】
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号
子串的长度。
示例 1:
输入:s = “(()”
输出:2
解释:最长有效括号子串是 “()”

本题的思路在于找到最后一个不匹配的 ‘)’ ,并记录对应的下标,这些下标将整个字符串分割成多个子串,每个子串都是一个完整有效的括号。

class Solution:
    def longestValidParentheses(self, s):
        if len(s) == 0 or len(s) == 1:
            return 0
        stack = [] # 
        j = 0
        max_len = 0
        while j < len(s):
            if s[j] == "(":
                stack.append(j)
            if s[j] == ")":
                if len(stack) and s[stack[-1]] == "(":
                    stack.pop()
                    if len(stack):
                        lens = j - stack[-1]
                        if lens > max_len:
                            max_len = lens
                    else:
                        lens = j + 1
                        if lens > max_len:
                            max_len = lens
                else:
                    stack.append(j)
            j += 1
        return max_len

2、单调队列

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。
在这里插入图片描述

本题目的思考在于如何在不超时的情况下找到子数组的最大值,如果直接通过队列每次进出一个元素,在剩下的队列中直接调用Max()函数会导致超时,所以这里需要调用单调队列的方法。

什么是单调队列?这同样是一种队列,但是队列要求从队列出口到入口的元素是从大到小排列的,那么我们要找到最大值的话,直接从出口弹出一个元素就可以了。

但是单调队列的入队和出队方法需要重新定义:

class mydeque():
    def __init__(self):
        self.deque = collections.deque()
    def pop(self, value):
        # 比较当前要弹出来的元素是否是站顶元素,如果是的话才会弹出
        if self.deque and self.deque[0] == value:
            self.deque.popleft()
    def push(self, value):
        while self.deque and self.deque[-1] < value:
            self.deque.pop()
        self.deque.append(value)
    def front(self):
        return self.deque[0]

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        stack = mydeque()
        res = []
        for i in range(k):
            stack.push(nums[i])
        res.append(stack.front())
        for i in range(k,len(nums)):
            stack.pop(nums[i - k])
            stack.push(nums[i])
            res.append(stack.front())
        return res
  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值