150. 逆波兰表达式求值
力扣题目链接(opens new window)
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
- 输入: ["2", "1", "+", "3", " * "]
- 输出: 9
- 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
-
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
-
适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
from operator import add, sub, mul
def div(x,y):return int(x/y) if x*y > 0 else -(abs(x)//abs(y))
class Solution:op_map = {'+': add, '-': sub, '*': mul, '/': div}def evalRPN(self, tokens: List[str]) -> int:# tokens = list(tokens)stack = []for i in tokens:if i not in {'+', '-', '*', '/'}:stack.append(int(i))else:op2 = stack.pop()op1 = stack.pop() # 这里是难点,"4","13","5","/","+"当到/的时候,第一个pop取出的是5,第二个pop取出的是13stack.append(self.op_map[i](op1, op2))return stack.pop()
239. 滑动窗口最大值
力扣题目链接(opens new window)
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
from collections import dequeclass MyQUeue:def __init__(self):self.queue = deque()def push(self, value):while self.queue and value > self.queue[-1]:self.queue.pop()self.queue.append(value)def pop(self, value):if self.queue and value == self.queue[0]:self.queue.popleft() # 把最大的元素pop掉,开始添加新元素了def front(self):return self.queue[0]class Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:que = MyQUeue()result = []for i in range(k):que.push(nums[i])result.append(que.front())for i in range(k, len(nums)):que.pop(nums[i-k]) #滑动窗口移除最前面元素que.push(nums[i])result.append(que.front())return result
思路:
1)push:如果push的元素比前元素大,直接把前面元素删掉,
2)pop:当要pop的值等于que的第一个(最大值)的时候说明这个值要真的被pop掉了,和他本身大小无关,只是滑窗滑到下一个了。
3)front:对于queue序列来说,第一个值queue[0],一直是最大值
347.前 K 个高频元素
力扣题目链接(opens new window)
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
示例 2:
- 输入: nums = [1], k = 1
- 输出: [1]
class Solution:def topKFrequent(self, nums: List[int], k: int) -> List[int]:map_ = {}for i in range(len(nums)):map_[nums[i]] = map_.get(nums[i], 0)+1pri_que = [] # 小顶堆for key, freq in map_.items():heapq.heappush(pri_que, (freq, key))if len(pri_que) > k:heapq.heappop(pri_que)result = [0] * kfor i in range(k-1, -1, -1):result[i] = heapq.heappop(pri_que)[1]return result
-
for key, freq in map_.items():
- 这个循环遍历字典
map_
的所有键值对。 key
是字典中的键(通常表示某个元素)。freq
是字典中对应键的值(表示该元素的频率)。
- 这个循环遍历字典
-
heapq.heappush(pri_que, (freq, key))
- 使用
heapq.heappush
函数将元素(freq, key)
推入优先队列pri_que
中。 - 这里使用的是一个小顶堆(默认情况下
heapq
实现的是小顶堆),堆中的每个元素是一个元组(freq, key)
,其中freq
是元素的频率,key
是元素的值。 - 小顶堆的特性是堆顶元素总是最小的,因此当我们插入
(freq, key)
时,堆会自动调整顺序,使频率最小的元素保持在堆顶。
- 使用
-
if len(pri_que) > k:
- 检查堆
pri_que
的大小是否超过了k
。 - 如果堆中元素数量超过了
k
,说明堆中已经有超过k
个元素。
- 检查堆
-
heapq.heappop(pri_que)
- 如果堆的大小超过了
k
,使用heapq.heappop
将堆顶元素弹出。 - 由于这是一个小顶堆,堆顶的元素是堆中频率最小的元素,所以弹出操作会移除当前频率最小的那个元素。
- 通过这种方式,堆的大小始终保持在
k
,并且堆中只保留频率最高的k
个元素。
- 如果堆的大小超过了