代码训练营 Day11 | 150. 逆波兰表达式求值 | 239. 滑动窗口最大值 | 347.前 K 个高频元素

150. 逆波兰表达式求值

逆波兰表达式(后缀表达式)

  1. (1+2)x(3+4)的后续表达顺序是: 左右中
  2.   后缀表达式:12+34+x

使用栈 思路

1. 遇见数字就放入栈,遇见操作运算符,取出栈里的数字进行运算

2. 每次取元素的时候只取两个元素

3. 结果就是栈最后的元素

class Solution(object):
    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """
        # create a stack
        stack = []

        # iterate the array
        for i in range(len(tokens)):
            # if we met the operater
            if tokens[i] == '+' or tokens[i] == '-' or tokens[i] == '*' or tokens[i] == '/':
                # since it's operater, we need prepare number 
                num1 = stack.pop()
                num2 = stack.pop()

                # plus
                if tokens[i] == '+':
                    stack.append(int(num2+num1))
                # minus
                elif tokens[i] == '-':
                    stack.append(int(num2-num1))
                # mul
                elif tokens[i] == '*':
                    stack.append(int(num2*num1))
                # div
                elif tokens[i] == '/':
                    # aviod round down, and if it's ngeative number abs first and use negative sign
                    result = int(num2 / num1) if num2 * num1 > 0 else -(abs(num2) // abs(num1))
                    stack.append(result)
            
            # if it is number
            else:
                # put the number into stack
                stack.append(int(tokens[i]))
        
        # return answer
        return stack[-1]
        

239. 滑动窗口最大值(一刷理解思路即可)

1. 每滑动一次pop()一个元素,对应的也要push()一个元素

2. 每移动一个位置把遗弃的元素给pop掉,把新加入的元素push进来

3. 每次在get max value查看最大值

单调队列

  1. 如果队列有比当前元素小的元素,把队列前面全部元素弹出,直到前面的元素没有当前元素小的为止
    1. 这样就可以维护最大值
  2. push的规则:
    1. 如果push进来的元素比前面大,弹出前面的元素,直到前面的元素比当前元素大为止
    2. 然后获取最大值
  3.   滑动窗口移动往后移动一位
  4.  最大值一直是维护在我们队列的出口处
    1. pop是只有在;出口元素是之前窗口最大值的时候才pop,其他情况push就把不相关的元素弹走了
    2. 弹出的元素和队列的出口处的元素相同的话
    3. 说明弹出的元素是当前滑动窗口的最大值
from  collections import deque
class MyQueue: # 单调队列(从大到小)
    def __init__(self):
        self.queue = deque() #这里需要使用deque实现单调队列,直接使用list会超时
    
    # 每次弹出的时候,比较当前的数值是否等于队列出口的数值,如果等于则弹出
    # 同时pop之前判断队列当前是否为空
    def pop(self,value):
        if self.queue and value == self.queue[0]:
            self.queue.popleft()

    # 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
    # 这样就保持了单调从大到小,队列口是最大值
    def push(self,value):
        # 判断是否需要弹出除了我们push的value以外的所有元素
        while self.queue and value >= self.queue[-1]:
            self.queue.pop()
        # 添加元素
        self.queue.append(value)
    
    # 查询目前队列里最大值并返回;直接返回队列前端也就是front就可以了。
    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]
        """
        que = MyQueue()
        result = []
        # 先将前k的元素放进队列
        for i in range(k):
            que.push(nums[i])
        #result记录前k的元素最大值
        result.append(que.front())
        # 根据k的值来滑动窗口
        for i in range(k,len(nums)):
            # 滑动窗口移除最前面的元素
            que.pop(nums[i-k])
            # 滑动窗口前加入最后面的值
            que.push(nums[i])
            # 记录对应的最大值
            result.append(que.front())
        
        return result
        

347.前 K 个高频元素

MAP思路

1. 对元素出现频率进行排序的话使用map

2. key: 是存放我们这里边的元素

3. value: 就是我们元素出现的次数

4. 以value做一个从大到小的排序

5. 输出前k个元素

大顶堆小顶堆 思路

1. 擅长在很大的数据集中求前k个高频或者低频的一个操作

2. 大顶堆: 头部的元素都要比孩子节点的元素大;根节点是最大的元素

3. 小顶堆: 根节点是最小的元素;父亲总是要比左右两个孩子的数值要小

4. 用堆来遍历一遍map里面所有的元素,然后堆里就维持k个元素

5. 使用小顶堆来实现: 每次push进来一个新元素,也要pop一个堆顶的元素

   1. 由于小顶堆根节点是最小值,每次push新元素进来都会把最小的给pop出去

   2. 遍历完成之后只会有最大的值留在堆里面

import heapq
class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 统计元素出现的频率
        map_ = {} # nums[i] 对应出现的次数
        for i in range(len(nums)):
            map_[nums[i]] = map_.get(nums[i],0)+1

        
        # 对频率排序
        # 定义一个小顶堆,大小为K
        pri_que = [] # 小顶堆

        # 用固定大小为K的小顶堆,扫描所有频率的数量
        for key,freq in map_.items():
            heapq.heappush(pri_que,(freq,key))
            if len(pri_que) > k:
                # 如果堆的大小小于了K,则队列弹出,保证堆的大小一直为k
                heapq.heappop(pri_que)
            
        
        # 找出前K个高频元素,因为小顶堆先弹出是最小的,所以倒叙来输出数组
        result = [0] * k
        for i in range(k-1,-1,-1):
            result[i] = heapq.heappop(pri_que)[1]

        return result

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值