数据结构与算法—-复习Part 9 (堆栈与单调栈)

本系列是算法通关手册LeeCode的学习笔记

算法通关手册(LeetCode) | 算法通关手册(LeetCode) (itcharge.cn)

本系列为自用笔记,如有版权问题,请私聊我删除。

目录

一,堆栈(Stack)

堆栈的顺序存储

堆栈的链式存储

例题

二,单调栈(Monotone Stack)

单调递增栈

单调递减栈

例题


一,堆栈(Stack)

        简称为栈,是一种只允许在表的一端进行插入和删除操作的线性表。

        把栈中允许插入和删除的一端称为 栈顶(top);另一端称为 栈底(bottom)。当表中没有任何数据元素时,称之为空栈。

        堆栈有【入栈】和【出栈】两种基本操作。

        是一种【后进先出(LIFO,Last In First Out)】的线性表。

         基本操作有:

                初始化空栈:创建一个空栈,定义栈的大小 size,栈顶指针 top;

                判断栈是否为空:为空,返回 True,否则返回 False。用于出栈和获取栈顶元素;

                判断栈是否已满:已满,返回 True,否则返回 False。用于入栈;

                入栈:在最后元素之后插入一个新的数据元素,并改变栈顶指针 top 的位置;

                出栈:删除最后一个数据元素,并改变栈顶指针 top 的位置;

                获取栈顶元素:获取最后位置的数据元素,不改变栈顶指针的位置。


堆栈的顺序存储

        顺序栈即堆栈的顺序存储结构,利用一组地址连续的存储单元依次存放自栈底到栈顶的元素,同时使用指针 top 指示栈顶元素在顺序栈中的位置。

       

实现代码:

class Stack:
    # 初始化空栈
    def __init__(self, size = 100):
        self.size = size
        self.stack = []
        self.top = -1

    # 判断栈是否为空
    def isEmpty(self):
        return self.top == -1

    # 判断栈是否已满
    def isFull(self):
        return self.top + 1 == self.size
        # top 从 -1 开始

    # 入栈操作
    def push(self, value):
        if self.isFull():
            raise Exception('Stack if full.')
        else:
            self.stack.append(value)
            self.top += 1

    # 出栈操作
    def pop(self):
        if self.isEmpty():
            raise Exception('Stack is empty.')
        else:
            self.stack.pop()
            self.top -= 1

    # 获取栈顶元素
    def peek(self):
        if self.isEmpty():
            raise Exception('Stack is empty.')
        else:
            return self.stack[self.top]

堆栈的链式存储

        链式栈即堆栈的链式存储结构。利用单链表的方式来实现堆栈,栈中元素按照插入顺序依次插入到链表的第一个节点之前,top 指针永远指向链表的头节点位置。

实现代码:

class Node:
    def __init__(self, val = 0, next = None):
        self.val = val
        self.next = next

class Stack:
    # 初始化空栈
    def __init__(self):
        self.top = None

    # 判断栈是否为空
    def isEmpty(self):
        return self.top == None

    # 入栈操作
    def push(self, value):
        node = Node(value)
        node.next = self.top
        self.top = node

    # 出栈操作
    def pop(self):
        if self.isEmpty():
            raise Exception('Stack is empty.')
        else:
            cur = self.top
            self.top = self.top.next
            del cur

    # 获取栈顶元素
    def peek(self):
        if self.isEmpty():
            raise Exception('Stack is empty.')
        else:
            return self.top.val

例题

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

        括号匹配是栈结构的经典应用;

        首先查看 s 的长度是否为偶数;

        使用栈结构,若是左括号则入栈,右括号且与栈顶匹配,则出栈;

        若栈为空,则返回 True,否则返回 Fasle

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

        时间复杂度 O(n)

        空间复杂度 O(1)

227. 基本计算器 II - 力扣(LeetCode)

        实现计算器是栈的经典应用;

        将第一个数字入栈,从第二个数字 num 开始,数字前的符号记为 op;

        若 op = + ,将 num 入栈,若 op = -,将 -num 入栈;

        若 op = *,取出栈顶元素 top ,将 top * num 入栈;

        若 op = / ,取出栈顶元素 top ,将 top // num 入栈;

        对栈内所有元素求和。

class Solution:
    def calculate(self, s: str) -> int:
        size = len(s)
        stack = []
        op = '+'
        index = 0
        while index < size:
            if s[index] == ' ':
                index += 1
                continue
            if s[index].isdigit():
                num = ord(s[index]) - ord('0')
                while index + 1 < size and s[index+1].isdigit():
                    index += 1
                    num = 10 * num + 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))
            elif s[index] in "+-*/":
                op = s[index]
            index += 1
        return sum(stack)

        时间复杂度 O(n)

        空间复杂度 O(n)

二,单调栈(Monotone Stack)

        一种特殊的栈。在栈 LIFO 的规则基础上,要求从栈顶到栈底的元素单调。

单调递增栈

        只有比栈顶元素小的元素才能直接进栈,否则需要将栈中比当前元素小的元素出栈,再将当前元素入栈。

代码模板: 

def monotoneIncreasingStack(nums):
    stack = []
    for num in nums:
        while stack and num >= stack[-1]:
            stack.pop()
        stack.append(num)

单调递减栈

        只有比栈顶元素大的元素才能直接进栈,否则需要先将栈中比当前元素大的元素出栈,再将当前元素入栈。

代码模板:

def monotoneDecreasingStack(nums):
    stack = []
    for num in nums:
        while stack and num <= stack[-1]:
            stack.pop()
        stack.append(num)

例题

单调栈适用于从端点处找第一个大于标准数的元素。

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

        nums1 是 nums2 的子集,且没有相同元素;

        可以使用单调栈遍历 nums2,若当前元素大于栈顶元素,则记录当前元素入哈希表;

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = []
        stack = []
        num_map = dict()
        for num in nums2:
            while stack and num > stack[-1]:
                num_map[stack[-1]] = num    # 如 stack = [1, 3, 5] num = 4
                                            # 元素 1 能入栈说明还没找到右侧比 1 大的元素
                                            # 此时将元素 1 出栈,并记录 num_map[1] = 4
                                            # 意为 比 1 大的第一个元素是4
                stack.pop()
            stack.append(num)
        for num in nums1:
            res.append(num_map.get(num, -1))
        return res

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

        单调栈在使用时,应注意需要返回的元素是什么,以此为基础决定如何构造单调栈。

        

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

算法通关手册(LeetCode) | 算法通关手册(LeetCode)

原文内容在这里,如有侵权,请联系我删除。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>