day12,python算法打卡,栈与队列2

  今日任务:

1)20. 有效的括号

2)1047. 删除字符串中的所有相邻重复项

3)150. 逆波兰表达式求值

4)239. 滑动窗口最大值

20. 有效的括号

题目链接:20. 有效的括号 - 力扣(LeetCode)

文字及视频讲解:代码随想录 (programmercarl.com)

思路:

由于栈先进后出的结构,我们可以使用栈,这样就可以做到括号的前后匹配。

首先要弄清楚,字符串里的括号不匹配有几种情况。

        1)字符串里左方向的括号多余了: 

        解决办法:发现已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false

        2)括号没有多余,但是 括号的类型没有匹配上:

        解决办法:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false

        3)字符串里右方向的括号多余了:

        解决办法:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        
        # 使用list
        stack = []

        for item in s:
            if item =='(':
                stack.append(')')
            elif item =='{':
                stack.append('}')
            elif item =='[':
                stack.append(']')
            elif  not stack or stack[-1] != item:
                return False
            else:
                stack.pop()
        
        if not stack:
            return True
        else:
            return False

感想:

         由于栈结构的特殊性,非常适合做对称匹配类的题目。

1047. 删除字符串中的所有相邻重复项

题目链接:1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)

文字及视频讲解:代码随想录 (programmercarl.com)

思路:

 这也是匹配问题,20. 有效的括号 是匹配左右括号,本题是匹配相邻元素,最后都是做消除的操作。

方法一:使用栈

方法二:双指针

方法一:使用栈

class Solution(object):
    def removeDuplicates(self, s):
        """
        :type s: str
        :rtype: str
        """
        stack = list()
        for item in s:
            if stack and stack[-1] == item:
                stack.pop()
            else:
                stack.append(item)

        return ''.join(stack)

 方法二:双指针

class Solution:
    def removeDuplicates(self, s: str) -> str:
        res = list(s)
        slow = fast = 0
        length = len(res)

        while fast < length:
            # 如果一样直接换,不一样会把后面的填在slow的位置
            res[slow] = res[fast]
            
            # 如果发现和前一个一样,就退一格指针
            if slow > 0 and res[slow] == res[slow - 1]:
                slow -= 1
            else:
                slow += 1
            fast += 1
            
        return ''.join(res[0: slow])

感想:

        匹配问题优先使用栈,看看是否可以解决问题。

150. 逆波兰表达式求值

题目链接:150. 逆波兰表达式求值 - 力扣(LeetCode)

文字及视频讲解:代码随想录 (programmercarl.com)

思路:

        首先先了解一下什么是逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。

        所以适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。

class Solution(object):
    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """

        stack = list()

        for item in tokens:

            if item not in {'+', '-', '*' ,'/'}:
                stack.append(int(item))
            else:
                num1 = stack.pop()
                num2 = stack.pop()
                if item == '+':
                    result = num1 + num2
                elif item == '-':
                    result = num2 - num1  # 注意减法的顺序
                elif item == '*':
                    result = num1 * num2
                elif item == '/':
                    if num1 *num2 >0:
                        result = num2 // num1
                    else:
                        result = -(abs(num2)//abs(num1))
                stack.append(result)
        return int(stack.pop())

感想:

        思路不难,但是要注意一个小点,就是在遇到除法的时候,需要判断是否存在只有一个是负数的情况,因为整除函数会向下取整到最接近的整数,而当n1是负数时,向下取整意味着结果将是更小的整数。

239. 滑动窗口最大值

题目链接:239. 滑动窗口最大值 - 力扣(LeetCode)

文字及视频讲解:代码随想录 (programmercarl.com)

思路:

方法一:(暴力法)

        直接采用两层循环遍历数组,每次取出滑动窗口中最大值,提交超时,时间复杂度为O(kn)

方法二:(采用单调队列)

        1)首先,我们需要自己实现单调队列,队列中只维护最大值即可。

        2)怎么实现呢?

              对于push函数:当进来一个数时,比较其与队列中最后一个数的大小;若新增数大,则在弹出队列中的数。若队列中的数大,则直接在队列后面添加新增数。

              第一次遍历k个元素后,现在需要将队列进行前移,此时我们要将需要将最前面的元素弹出,同时新增一个数,重复2)过程

              对于pop函数:由于push的时候第一个数只保存为最大的元素,因此比较小的数早就被弹出去了,所以此时只需要判断队列第一个数是否等于此时列表k的第一个数,等于的话就说明需要pop出这个最大的值了。

方法一:(暴力法)

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """

        left = 0
        max_result = float('-inf')
        result = []
        while left <= len(nums) - k:
            list1 = []
            for i in range(k):
                list1.append(nums[i+left])
            left += 1
            result.append(max(list1))

        return result

 方法二:(单调队列法)

from collections import deque

class myquene: #单调队列(从大到小
    def __init__(self):
        self.queue = deque()  #这里需要使用deque实现单调队列,直接使用list会超时

    #如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
    #这样就保持了队列里的数值是单调从大到小的了。
    def push(self,value):
        while self.queue and self.queue[-1]<value:
            self.queue.pop() # 注意一下这是pop
        self.queue.append(value)

    #每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
    #同时pop之前判断队列当前是否为空。
    def pop(self,value):
        if self.queue and self.queue[0] == value:
            self.queue.popleft() # 注意一下这是popleft

    #查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
    def get_max(self):
        return self.queue[0]


class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        result = []
        left = 0
        queue = myquene()

        for i in range(k):  #先将前k的元素放进队列
            queue.push(nums[i])
            
        result.append(queue.get_max()) #result 记录前k的元素的最大值

        while left < len(nums) - k:
            queue.pop(nums[left]) #滑动窗口移除最前面元素
            queue.push(nums[left + k ]) #滑动窗口前加入最后面的元素
            result.append(queue.get_max()) #记录对应的最大值
            left += 1

        return result

 感想:

        这题核心是要用单调队列结构。注意一下pop的左右顺序!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值