3 栈
1.1基础
只允许在一端进行插入或删除操作的线性表。
首先,栈是一种线性表,但限定这种线性表只能在某一段进行插入和删除操作。
-
时间复杂度
- Push (入栈):O(1)
- Pop (出栈):O(1)
- Access (访问栈顶):O(1)
-
两种实现方式
- 顺序栈:采用顺序存储结构可以模拟栈存储数据的特点,从而实现栈存储结构;
- 链栈:采用链式存储结构实现栈结构
-
区别: 物理存储位置区别--------------顺序栈底层采用的是数组,链栈底层采用的是链表
-
顺序栈实现及基本操作
class Stack:
#初始化
def __init__(self, size = 100):
self.top = -1
self.size = size
self.stack = []
#判断是否为空
def is_None(self):
return self.top == -1
#判断是否满栈
def is_full(self):
return self.top + 1 == self.size
#入栈
def push(self, val):
if self.is_full():
raise Exception("Stack is full!")
else:
self.stack.append(val)
self.top += 1
#出栈
def pop(self):
if self.is_None():
raise Exception("Stack is empty")
else:
self.stack.pop()
self.top -= 1
#获得栈顶
def peek(self):
if self.is_None():
raise Exception("Stack is empty")
else:
return self.stack[self.top]
- 链栈实现及基本操作
class ListNode:
def __init__(self, val):
self.val = val
self.next = next
class Stack:
#初始化
def __init__(self):
self.top = None
def is_None(self):
return self.top == None
def push(self, val):
cur = ListNode(val)
cur.next = self.top
self.top = cur
def pop(self):
if self.is_None():
raise Exception("Stack is empty")
else:
cur = self.top
self.top = self.top.next
del cur
def peek(self):
if self.is_None():
raise Exception("Stack is empty")
else:
return self.top.val
1.2 题目
1.2.1 20 . 有效的括号
- 思路: 哈希 + 栈 >>>> 利用哈希记录括号合法相关关系 >>> 左括号优先入栈, 直到出现第一个右括号 >>> 判断第一右括号是否与栈顶合法配对 >>> 配对成功栈顶出栈 >>> 直到栈非空则False, 栈为空则True
class Solution:
def isValid(self, s: str) -> bool:
d = { "}":"{",
"]":"[",
")":"(" }
stack = []
for k in s:
if k not in d:
stack.append(k)
else:
if stack and d[k] == stack[-1]:
stack.pop()
else:
return False
return not stack
1.2.2 150 . 逆波兰表达式求值
- 思路: 建立新栈 >>> 数字入栈, 遇到符号考虑
stack[-1]
和stack[-2]
的运算 >>> 注意:isdigit()
只能判断正数 ; 除法应该用int()
确保整型
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token[-1].isdigit(): # 考虑到负数使用token[-1]
stack.append(int(token))
else:
p = stack.pop()
if token == "+":
stack[-1] += p
elif token == "-":
stack[-1] -= p
elif token == "*":
stack[-1] *= p
elif token == "/":
stack[-1] = int(stack[-1] * 1/p)
return stack[-1]
1.2.3 155 . 最小栈
- 思路: 考虑利用两个栈 >>>
minstack[-1]
来表示当前链表最小值 >>> 当pop
,push
栈时更新minstack
class MinStack:
def __init__(self):
self.stack = []
self.minstack = []
def push(self, val: int) -> None:
self.stack.append(val)
if not self.minstack or self.minstack[-1] >= val:
self.minstack.append(val)
def pop(self) -> None:
if self.stack[-1] == self.minstack[-1]:
self.minstack.pop()
self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.minstack[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
1.2.4 844 . 比较含退格的字符串
- 思路一: 栈 >>> 两栈对比是否相等解决
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
stack_1, stack_2 = [], []
for i in s:
if stack_1 and i == "#":
stack_1.pop()
elif i != '#':
stack_1.append(i)
for j in t:
if stack_2 and j == "#":
stack_2.pop()
elif j != '#':
stack_2.append(j)
return stack_1 == stack_2
- 思路二: 空间复杂 O(1) ----- 快慢指针 >>>>
fast
遍历字符串, 遇到#
slow
左移, 否则右移
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
def backspace(s):
fast, slow = 0, 0
s = list(s)
while fast < len(s):
if s[fast] != '#':
s[slow] = s[fast]
slow += 1
elif slow > 0:
slow -= 1
fast += 1
return s[:slow]
return backspace(s) == backspace(t)
1.2.5 227 . 基本计算器 II
- 思路:
加法 >>> num入栈
减法 >>> -num入栈
乘法 >>> 栈顶*num 入栈
除法 >>> 栈顶 / num 入栈
最后计算栈和
class Solution:
def calculate(self, s: str) -> int:
op = '+'
stack = []
num = 0
for i in range(len(s)):
if s[i].isdigit():
num = num * 10 + int(s[i])
if i == len(s) - 1 or s[i] in "+-*/":
if op == '+':
stack.append(num)
elif op == '-':
stack.append(-num)
elif op == '*':
stack.append(stack.pop() * num)
elif op == '/':
stack.append(int(stack.pop() / num))
num = 0
op = s[i]
return sum(stack)