代码随想录算法训练营第十一天 | 栈与队列part02

68 阅读4分钟

代码随想录算法训练营第十一天 | 栈与队列part02

150 逆波兰表达式求值

image.png

思路:用栈来进行数字的存储,遇见数字就存入栈中,遇见操作符就从栈中取出元素,做一个计算,然后再加入栈中。

自己做的,代码并不规范,但是力扣可以通过

tokens = ["4","-2","/","2","-3","-","-"]
stack_in = []
for i in tokens:
    if i != '+' and i != '-' and i != '*' and i != '/':
        stack_in.append(i)
    else :
        x1 = int(stack_in.pop())
        x2 = int(stack_in.pop())
        if i == '+':
            stack_in.append(x2+x1)
        elif i == '-':
            stack_in.append(x2-x1)
        elif i == '*':
            stack_in.append(x2*x1)
        elif i == '/':
            if x2//x1 < 0:
                if x2 % x1 == 0 : 
                    stack_in.append(x2//x1)
                else :
                    stack_in.append(x2//x1 + 1)
            else :
                stack_in.append(x2//x1)
print(stack_in)

参考代码:虽然没有快多少,但是代码很简洁。

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(object):
    op_map = {'+': add, '-': sub, '*': mul, '/': div}
    
    def evalRPN(self, tokens):
        stack = []
        for token in tokens:
            if token not in {'+', '-', '*', '/'}:
                stack.append(int(token))
            else:
                op2 = stack.pop()
                op1 = stack.pop()
                stack.append(self.op_map[token](op1, op2))  # 第一个出来的在运算符后面
        return stack.pop()

239 滑动窗口最大值 (有点难度,可能代码写不出来,但一刷至少需要理解思路)

image.png

正常思路如下,直接存一下每个滑动窗口的最大值,暴力解法,时间复杂度为o(n*k),在力扣上有很多测试点过不去。

nums = [1,3,-1,-3,5,3,6,7]
k = 3
# nums = [1]
# k = 1
slow = 0
fast = slow + k 
stack = []
while fast <= len(nums):
    max_ = nums[slow]
    for i in range(slow,fast):
        max_ = nums[i] if nums[i] > max_ else max_
    stack.append(max_)
    slow += 1
    fast += 1
print(stack)

优化思路:

双端队列(deque) :我们用双端队列来保存窗口内的元素索引,并确保队列的元素满足以下条件:

  • 队列中的元素按照从大到小的顺序排列。
  • 队列的第一个元素总是当前窗口的最大值(即队列的头部元素)。

滑动窗口

  • 对于每个新的元素,我们移除队列中不再可能成为最大值的元素。
  • 每次滑动窗口时,队列中的头部元素是当前窗口的最大值。
from collections import deque  # 引入双端队列(deque)def maxSlidingWindow(nums, k):
    result = []  # 用来保存结果
    dq = deque()  # 初始化双端队列
    
    for i in range(len(nums)):  # 遍历每一个元素
        # 1. 移除不在窗口内的元素(即队列头部的索引小于当前窗口的左边界)
        if dq and dq[0] < i - k + 1:
            dq.popleft()  # popleft() 弹出队列头部的元素
​
        # 2. 移除队列中所有比当前元素小的索引
        while dq and nums[dq[-1]] < nums[i]:
            dq.pop()  # pop() 弹出队列尾部的元素
​
        # 3. 将当前元素的索引加入队列
        dq.append(i)
        
        # 4. 当窗口大小达到k时,记录当前窗口的最大值
        if i >= k - 1:
            result.append(nums[dq[0]])  # 队列头部的索引对应的是当前窗口的最大值
​
    return result

详细的执行过程:

假设 nums = [1, 3, -1, -3, 5, 3, 6, 7]k = 3,我们来逐步执行代码。

  1. i = 0nums[i] = 1

    • 队列为空,直接把索引 0 加入队列。
    • 队列:[0]
  2. i = 1nums[i] = 3

    • nums[1] 比队列中的元素 nums[0] = 1 大,移除队列尾部的元素。
    • 队列变为空,加入索引 1
    • 队列:[1]
  3. i = 2nums[i] = -1

    • nums[2] 比队列中的元素 nums[1] = 3 小,不需要移除。
    • 加入索引 2
    • 队列:[1, 2]
    • 当前窗口大小为 3,队列头部索引 1 对应的值是 3,所以当前窗口最大值是 3
  4. i = 3nums[i] = -3

    • nums[3] 比队列中的元素 nums[2] = -1 小,不需要移除。
    • 加入索引 3
    • 队列:[1, 2, 3]
    • 当前窗口最大值仍是 3
  5. i = 4nums[i] = 5

    • nums[4] 比队列中的元素 nums[3] = -3nums[2] = -1nums[1] = 3 都大,依次移除队列尾部的元素。
    • 队列:[4]
    • 当前窗口最大值是 5
  6. i = 5nums[i] = 3

    • nums[5] 比队列中的元素 nums[4] = 5 小,不移除。
    • 加入索引 5
    • 队列:[4, 5]
    • 当前窗口最大值是 5
  7. i = 6nums[i] = 6

    • nums[6] 比队列中的元素 nums[5] = 3nums[4] = 5 都大,依次移除队列尾部的元素。
    • 队列:[6]
    • 当前窗口最大值是 6
  8. i = 7nums[i] = 7

    • nums[7] 比队列中的元素 nums[6] = 6 大,移除队列尾部的元素。
    • 加入索引 7
    • 队列:[7]
    • 当前窗口最大值是 7

347 前 K 个高频元素 (有点难度,可能代码写不出来,一刷至少需要理解思路)

image.png

nums = [1,1,1,2,2,3] 
k = 2
dict_ = dict()
for i in nums:
    dict_[i] = dict_.get(i,0) + 1
dict_ = sorted(dict_.items(),key=lambda x:x[1],reverse=True)
list_ = []
for i in dict_[:k]:
    list_.append(i[0])
print(list_)