day11 代码随想录 | 150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元素

逆波兰表达式求值

给你一个字符串数组 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
    

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值