逆波兰表达式求值
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
这个题目是栈的典型应用。运算的时候,每次是两个数进行就算符操作。
用栈的数据结构去完成。
1. 遇到数字就入栈
2. 遇到运算符就 pop两个数字根据符号进行运行
这里注意几个细节。
1. 在使用除法的时候,要定义函数,来针对负数的除法专门写函数(主要是针对负数。比如 -12 // 5,我们想的是为-2,但是python计算式-3. 我们取绝对值然后再除)
2. pop数字运算的顺序。应该是后pop的数去运算前pop的数。比如[1, 2 /] 是 1 // 2 你先pop的是2 在pop是1。
3. 由于你最后输出的数字,因此你每次入栈的时候,要将字符转换为数字。不然如果只输入一个数字,你将输入一个字符,会报错。
def evalRPN(tokens: List[str]) -> int:
stack = []
calculators = ["+", "-", "*", "/"]
for i in tokens:
if i in calculators:
num1 = stack.pop()
num2 = stack.pop()
if i == "+":
stack.append(num1 + num2)
elif i == "-":
stack.append(num2 - num1)
elif i == "*":
stack.append(num1 * num2)
else:
stack.append(div(num2, num1))
else:
stack.append(int(i))
return stack.pop()
def div(x, y):
return int(x/y) if x*y > 0 else: - (abs(x)//abs(y))
滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
暴力法:
如果没想到的一个好的方法,那就是得到每一个窗口,每个窗口求最大。代码如下
def maxSlidingWindow(nums: List[int], k: int):
res = []
for i in range(0, len(nums)-1):
if i + k <= len(nums):
window = nums[i:i+k]
res.append(max(window))
return res
单调队列的解法
单调队列的思想就是我维护一个队列,这个队列有三个函数
1. pop() 删除队首元素,当我们滑动窗口移动,你需要将窗口外的元素删除
2. push 入队元素。这里入队元素有讲究。我入队的是窗口最大的元素和之后可能成为最大的元素。比如当前窗口元素为1,3,2. 我先入队1, 当我想要入队3时,需要先删除1,然后再入队3,当入队2时,因为2小于,他可能成为之后窗口最大的元素,所以入队。这样队列中存在的元素就是3,2 是单调的
3. getMaxValue. 直接出队队首元素。
维护这个队列后,我们就去遍历列表。首先,先要初始化队列,先让第一个窗口构建优先级队列,然后再滑动。
from collections import deque
class MyQueue:
def __init__(self):
self.queue = deque()
def pop(self, val):
if (self.queue and self.queue[0] == val):
self.queue.popleft()
def push(self, val):
while (self.queue and self.queue[-1] < val):
self.queue.pop()
self.queue.append(val)
def getMaxValue(self):
return self.queue[0]
def maxSlidingWindow(nums: List[int], k: int) -> List[int]:
queue = MyQueue()
res = []
for i in range(k):
queue.push(nums[i]):
res.append(queue.getMaxValue())
for i in range(k, len(nums)):
queue.pop(nums[i-k])
queue.push(nums[i])
res.append(queue.getMaxValue())
return res
前 K 个高频元素
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
这个题呢,要考察的就是优先级队列,也就是小顶堆。队首出元素,队尾进元素。
常规思路也能做,其实要做的就以下三个步骤
1. 得到每个元素的频率
2. 对频率进行排序
3. 得到前K个元素
常规思路(不用特殊的数据结构)
先构建一个字典,key是出现的数字,value是它的频率
然后我在构建一个字典,将频率作为key,对应的value是key构成的list
然后对key进行排序,然后取前k个。
def topKFrequent(nums: List[int], k: int):
from collections import defaultdict
cnt_dict = defaultdict(int)
for num in nums:
cnt_dict[num] += 1
index_dict = defaultdict(list)
for num, freq in cnt_dict.items():
index_dict[freq].append(num)
key = list(index.dict.keys())
key.sort() # 升序
res = []
cnt = 0
while cnt != k and key:
res += index_dict[key[-1]
cnt += len(index_dict[key[-1]])
key.pop()
return res[0: k]
使用优先级队列(小顶堆)
小顶堆一直维护的是我们的freq, value。大小就是为k
import heapq
from collections import defaultdict
def topKFrequent(nums: List[int], k: int):
dic = defaultdict(int)
for num in nums:
dic[num] += 1
pri_que = []
# 用固定大小的k的小顶堆,扫描所有的频率
for key, freq in dic.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k:
heapq.heappop(pri_que)
# 找出前K个高频元素
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.headpop(pri_que)[1]
return result