LeetCode 150.逆波兰表达式求值:
文章链接
题目链接:150.逆波兰表达式求值
思路:
① 使用栈进行运算,遇到操作数入栈,遇到运算符出栈两个元素后入栈
② 需要注意的是:所给的算式为string类型,需要转换为 int / long long类型后入栈;且题目要求除法为向零截断,操作数可能为负数(-2 / 3 = -1),因此除法需要先判断操作数的正负后再进行除法运算
逆波兰表达式:
- 是一种后缀表达式,也就是运算符写在后面的表达式。比如(1 + 2) * (3 + 4) 转换为逆波兰表达式即 ( ( 1 2 + ) ( 3 4 + ) * )。
- 优点如下:
- 去掉括号后无歧义,即去掉括号后也可以按照次序计算出正确结果
- 使用用栈运算:遇到数字则入栈;遇到运算符弹出栈顶两个数字进行计算,并将结果压入栈中。(第二个弹出的是第一个操作数)
python">"""
方法1:遇到运算符后逐个判断并进行运算
"""
def div(op1, op2):return op1 // op2 if op1 * op2 > 0 else -(abs(op1) // abs(op2))
class Solution(object):def evalRPN(self, tokens):""":type tokens: List[str]:rtype: int"""stack = []op_set = {'+', '-', '*', '/'}for token in tokens:if token not in op_set:stack.append(int(token))else:op2 = stack.pop()op1 = stack.pop() # 第二个弹出的为第一个操作数if token == '+': stack.append(op1 + op2)elif token == '-': stack.append(op1 - op2)elif token == '*' : stack.append(op1 * op2)else:stack.append(div(op1, op2))return stack.pop()
"""
方法2:借用operator库和字典实现字符运算符到实际的函数运算
"""
from operator import add, sub, mul
def div(op1, op2):return int(op1 / op2) if op1 * op2 > 0 else -(abs(op1) // abs(op2))class Solution(object):op_map = {'+':add, '-':sub, '*':mul, '/':div}def evalRPN(self, tokens):stack = []for token in tokens:if token not in self.op_map:stack.append(int(token))else:op2 = stack.pop()op1 = stack.pop() # 后出现的为第一个操作数stack.append(self.op_map[token](op1, op2))return stack.pop()
感悟:
需要注意细节:将操作数转换为整数类型,第二个弹出的为第一个操作数,正负数的向零截取除法
LeetCode 239.滑动窗口最大值:
文章链接
题目链接:239.滑动窗口最大值
思路:
使用队列保存窗口中的元素,那么滑动窗口的最大值由队列中得到,那么维持一个单调队列,最大值为队首元素,但是push和pop需要对队列进行调整比较麻烦。
那么维持一个“单调双端队列”
① push (value),若队尾元素 < value,出队队尾元素直到其值 >= value,从而维持了队列的单调。且需要返回的为滑动窗口最大值,要么出队的元素中没有队首最大值,对返回值无影响;要么出队元素中有队首最大值,那么value成为队首最大值。
② pop(value),队首出队,由于push时将 < push_value的值全部出队了,且出队只能出队首元素,因此value == 队首元素时才出队。(若value < queue.front(),那么该元素在push时已经出队,且对于滑动窗口的最大值无影响;value > queue.front(),这种情况不存在)
python">from collections import deque
class Myqueue(object):def __init__ (self):self.queue = deque() # 使用双端队列构造单调队列,左队头,右队尾def pop(self, value):# 当弹出元素为队首元素时才弹出if self.queue and value == self.front():self.queue.popleft()def push(self, value):# push元素到队尾,为了保持单调队列;一直弹出队尾元素直到队尾元素 >= valuewhile self.queue and self.queue[-1] < value:self.queue.pop()self.queue.append(value)# 队首元素即窗口的最大元素def front(self):return self.queue[0]
class Solution(object):def maxSlidingWindow(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""queue = Myqueue()result = []# 将前k个加入单调队列中for i in range(k):queue.push(nums[i])result.append(queue.front()) # 保存每个窗口的最大值for i in range(k, len(nums)):queue.pop(nums[i - k])queue.push(nums[i])result.append(queue.front())return result
感悟:
“单调”双端队列的一种实现和利用
LeetCode 347.前K个高频元素:
文章链接
题目链接:347.前K个高频元素
思路:
① 统计并记录元素的频率和元素本身:map
② 对元素频率进行排序
③ 根据排序后的元素频率得到前 k 个高频元素
采用大小为 k 的优先级队列,其中优先级为频率。使用大小为 k 的小根堆实现该优先级队列(每次压入元素时,直接从堆顶弹出最小值,然后压入元素,从而留下的 k 个元素为频率前 k 的元素)。
需要注意的是python中使用heapq包来实现小根堆。heapqpush(pri_que, value)只能根据value元素建立小根堆(想建立大根堆的话使用value的负值建立小根堆,输出元素时再取负值)。建立优先级队列为heappush(pri_que, (pri, value)),根据 pri 在 pri_que中建立最小堆
python">import heapq
class Solution(object):def topKFrequent(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""# 统计频率map_num = {}for num in nums:map_num[num] = map_num.get(num, 0) + 1# 构造大小为k的小根堆得到频率前 k 高的元素pri_que = []for num, fre in map_num.items():if len(pri_que) < k:heapq.heappush(pri_que, (fre, num))elif fre > pri_que[0][0]:heapq.heappop(pri_que)heapq.heappush(pri_que, (fre, num))# 倒序存储堆弹出的元素result = [0] * kfor i in range(k - 1, -1, -1):result[i] = heapq.heappop(pri_que)[1]return result
"""
方法2:转换字典为fre_num,然后单独对频率进行排序并取排序后前 k 个高频元素
"""
from collections import defaultdict
class Solution(object):def topKFrequent(self, nums, k):# 统计频率map_num = {}for num in nums:map_num[num] = map_num.get(num, 0) + 1# 反转字典 (fre: num)fre_num = defaultdict(list)for num, fre in map_num.items():fre_num[fre].append(num)# 对频率进行排序fre_key = list(fre_num.keys())fre_key.sort(reverse=True)# 取出现频率前 k 高的元素result = []cnt, i = 0, 0while cnt < k:result += fre_num[fre_key[i]]cnt += len(fre_num[fre_key[i]])i += 1return result
感悟:
优先级队列的实现和字典的反转
学习收获:
① 学会了使用小根堆实现优先级队列
② 学会了“单调”双端队列的一种实现