代码随想录第十天——LeetCode 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素

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取出的是13
                stack.append(self.op_map[i](op1, op2))
        return stack.pop()

239. 滑动窗口最大值

力扣题目链接(opens new window)

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

from collections import deque


class 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)+1

        pri_que = []  # 小顶堆

        for key, freq in map_.items():
            heapq.heappush(pri_que, (freq, key))
            if len(pri_que) > k:
                heapq.heappop(pri_que)
        
        result = [0] * k
        for 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 个元素。
  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\],可以使用暴力解法来求解滑动窗口最大值。具体的做法是,遍历数组,对于每个窗口,使用一个内部循环来找到窗口中的最大值,并将其存储在结果数组中。时间复杂度为O(n*k),其中n为数组长度,k为窗口大小。 根据引用\[2\],还可以使用队列来求解滑动窗口最大值。具体的做法是,使用一个双端队列来维护一个单调递减的窗口。遍历数组,对于每个元素,首先判断队头是否在滑动窗口范围内,如果不在,则将其从队头移除。然后,将当元素与队尾元素比较,如果当元素大于队尾元素,则将队尾元素移除,直到队列为空或者当元素小于等于队尾元素。最后,将当元素的索引插入队尾。如果滑动窗口元素个数达到了k个,并且始终维持在窗口中,就将队头元素加入答案数组中。时间复杂度为O(n),其中n为数组长度。 综上所述,可以使用暴力解法或者使用队列来求解leetcode滑动窗口最大值。 #### 引用[.reference_title] - *1* *3* [leetcode239. 滑动窗口最大值](https://blog.csdn.net/kkkkuuga/article/details/124829581)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode#239. 滑动窗口最大值 (Java解法)](https://blog.csdn.net/paranior/article/details/114890555)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值