线性数据结构
线性数据结构:栈、队列、双端队列和列表都是有序的数据集合,其元素的顺序取决于添加顺序或移除顺序。一旦某个元素被添加进来,它与前后元素的相对位置将保持不变。
栈
满足last-in-first-out,包含以下函数:
- Stack() 创建一个空栈
- push(item) 将一个元素添加到栈顶端
- pop() 移除栈顶元素,并返回值
- peek() 返回栈顶元素
- isEmpty() 检查是否为空,返回bool
- size() 返回栈中元素的数目
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[-1]
def size(self):
return len(self.items)
if __name__ == "__main__":
s = Stack()
s.push(12)
s.push('hello')
print(s.size())
print(s.pop())
print(s.size())
案例:括号匹配(不写了)
中序、前序、后序表达式
前后中指的是运算符的位置。在写前序时,先写运算符,再写左右两个操作数。如果有括号,先把括号里面的改成表达式,然后作为一个整体继续写表达式。如下表所示,前序和后序表达式并不需要括号,运算顺序就是包含在表达式的书写顺序里的。
中序表达式 | 前序表达式 | 后序表达式 |
---|---|---|
A + B | + A B | A B + |
A + B * C | + A * B C | A B C * + |
(A + B) * C | * + A B C | A B + C * |
以下基于这个假设:假设后序表达式是一个以空格分隔的字符串,运算符有±/,操作数是一位整数值*
中序转后序
算法:
- ans保存结果,op_stack保存运算符,prec保存各运算符的优先级
- 从左到右扫描表达式:当前字符为token
- 如果token是操作数,则添加到ans
- 如果token是(,则压入op_stack
- 如果token是),则反复从op_stack中pop元素添加到ans,直到遇到(
- 如果是运算符,要先从op_stack中取出优先级更高或相同的运算符,添加到ans,然后将token压入op_stack
- 如果此时op_stack不是空栈,则依次出栈添加到ans末尾
import string
def infixToPostfix(infix_expr):
prec = {'*':3, '/':3, '+':2, '-':2, '(':1}
op_stack = Stack() # 使用前面的Stack
ans = []
# 将表达式转为list
tokens = list(infix_expr.replace(' ', ''))
for token in tokens:
# 如果是操作数
if token in string.digits:
ans.append(token)
elif token == '(':
op_stack.push(token)
elif token == ')':
top_token = op_stack.pop()
while top_token != '(':
ans.append(top_token)
top_token = op_stack.pop() # 最后一个(也会被pop出去
else:
while (not op_stack.isEmpty()) and (prec[op_stack.peek()] >= prec[token]):
ans.append(op_stack.pop())
op_stack.push(token)
# 剩余的压入ans
while not op_stack.isEmpty():
ans.append(op_stack.pop())
return " ".join(ans)
if __name__ == "__main__":
print(infixToPostfix("(1+2)*(3+4)")) # 1 2 + 3 4 + *
print(infixToPostfix("5 + 6 * 7")) # 5 6 7 * +
计算后序表达式的值
- ans保存结果,op_stack保存操作数
- 从左到右扫描表达式:
- 如果是数字,转换为整数并压入op_stack
- 如果是运算符,从op_stack中pop栈顶两个元素,计算,然后将运算结果压入op_stack
- ans中的值是结果,返回即可
def postfixEval(postfix_expr):
op_stack = Stack()
tokens = postfix_expr.split()
for token in tokens:
if token in string.digits:
op_stack.push(token)
else:
op1 = op_stack.pop()
op2 = op_stack.pop()
op_stack.push(str(eval(op2 + token + op1)))
return op_stack.pop()
if __name__ == "__main__":
print(postfixEval(infixToPostfix("1 + 3*5"))) # 16
496. 下一个更大元素 I
https://leetcode.cn/problems/next-greater-element-i
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
思路:
先计算nums2的下一个更大元素字典,再用nums1直接查找即可。计算下一个更大元素字典时,使用list实现栈,原则是:弹出比当前元素小的元素,如果一个元素比当前元素大,那么它就是下一个更大元素。如果栈里没有元素了,说明找不到。从数组后面向前这样操作即可。
class Solution:
def getNextMax(self, nums):
arr = []
ans = []
for i in range(len(nums) - 1, -1, -1):
while len(arr) != 0 and arr[-1] <= nums[i]:
arr.pop()
if len(arr) == 0:
ans.append(-1)
else:
ans.append(arr[-1])
arr.append(nums[i])
return ans[::-1]
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
res = self.getNextMax(nums2)
d = {}
for i in range(len(nums2)):
d[nums2[i]] = res[i]
ans = []
for n in nums1:
ans.append(d[n])
return ans