代码随想录Day11 | LeetCode232. 用栈实现队列(模拟);225.用队列实现栈(模拟);20. 有效的括号(栈应用);1047. 删除字符串中的所有相邻重复项(栈应用)

LeetCode232.用栈实现队列

链接:232. 用栈实现队列 - 力扣(LeetCode)

1. 思路

  1. 一个输入栈,一个输出栈。

  1. 输入栈负责不停的push元素进去

  1. 输出栈有两种情况:

一,当输出栈(out stack)为空时,说明还没有调用任何的push或者peek操作,此时如果要进行push或者peek,首先要把输入栈(in stack)里面的所有元素pop出来,依次放入到输出栈里面,直到输入栈为空。接着我们返回输出栈的栈顶元素即可。

例如:in stack: 12345,out stack: empty,此时就要不停的把in stack元素pop出来,放入out stack,变成 in stack: empty, out stack: 54321, 最后返回out stack栈顶元素

二,当输出栈 (out stack) 不为空时,说明我们已经调用过push或者peek的操作了,那么此时无论in stack有没有继续掉用过push操作,我们都能够保证:out stack的栈顶元素一定就是最先入栈的那个元素。那么此时我们就不需要把 in stack元素放进 out stack,而是直接返回 out stack的栈顶元素即可。

4.简单的来说,这两种情况就可以归结为一种:检查out stack是否为空,如果是空,那么就把 in stack里面的所有元素倒进 out stack,最后返回 out stack 栈顶元素。如果out stack不为空,直接返回out stack 栈顶元素。

2.时空复杂度:

时间复杂度:push, empty 为O(1),peek和pop为均摊时间复杂度为O(1),因为每个元素至多入栈和出栈2次。-- 什么是均摊时间复杂度?因为这个题目里面,是否要把in stack元素全部倒入 out stack,以及倒入元素是多少,这个情况是不确定的,最坏情况下,每个元素会经历入栈和出栈的两次操作,那么其实均摊下来对于这个元素而言,时间复杂度就是O(1)

空间复杂度:空间复杂度在最坏情况下需要存储n个元素,因此是 O(N)

代码

class MyQueue:

    def __init__(self):
        self.stackIn = [] # 元素负责进栈
        self.stackOut = [] # 元素负责出栈

    def push(self, x: int) -> None: # push - O(1)
        self.stackIn.append(x)

    def pop(self) -> int:
        if not self.stackOut:
            while self.stackIn:
                self.stackOut.append(self.stackIn.pop())
        return self.stackOut.pop()

    def peek(self) -> int:
        if not self.stackOut:
            while self.stackIn:
                self.stackOut.append(self.stackIn.pop())
        return self.stackOut[-1]

    def empty(self) -> bool: # empty - O(1)
        if not self.stackOut and not self.stackIn:
            return True
        return False

LeetCode225. 用队列实现栈

链接:225. 用队列实现栈 - 力扣(LeetCode)

1. 思路

使用一个队列实现就够了。例如:12345

如果调用pop函数,那么保留队尾元素,变成 5 | 1234 接着popleft,就把5这个栈顶元素pop出来了

如果调用peek函数,那么直接返回队列的最后一个元素即可。(这个题比上面那个题简单多了)

2.代码

class MyStack(object):

    def __init__(self):
        self.q = collections.deque()

    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.q.append(x)

    def pop(self):
        """
        :rtype: int
        """
        n = len(self.q)
        for i in range(n-1): # 巧妙操作:通过计算queue的长度来保证不pop最后一个元素
            self.q.append(self.q.popleft())
        return self.q.popleft()


    def top(self):
        """
        :rtype: int
        """
        return self.q[-1]

    def empty(self):
        """
        :rtype: bool
        """
        if len(self.q) == 0: 
            return True
        else:
            return False
  1. 复杂度:

入栈self.push()

时间复杂度O(1),直接把元素append到queue中的最后就行;

空间复杂度O(1),queue 栈多储存一个元素;

出栈self.pop()# 只有pop操作的时间复杂度是O(N),因为需要把前面的n-1个元素重新入队

时间复杂度O(N),需要把除最后一个元素之外的所有元素全部弹出再压入队列中

空间复杂度O(N)需要额外的N个内存来储存栈中的元素;

取栈首元素self.top()

直接用deque的-1下标,时间复杂度O(1);空间复杂度O(1);

判断空self.empty()

只需要判断队列是否为空即可,时间复杂度O(1),空间复杂度O(1)


LeetCode20. 有效的括号

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

  1. 思路

先来分析一下 这里有三种不匹配的情况:(图片文字来自@努力学习的牛西宁)

第一种情况,字符串里左方向的括号多余了 ,所以不匹配。

第二种情况,括号没有多余,但是 括号的类型没有匹配上。

第三种情况,字符串里右方向的括号多余了,所以不匹配。

class Solution(object):
    def isValid(self, s):
       
        stack = []
        if not s:
            return True
        for item in s:
            if item == "(":
                stack.append(")")
            elif item == "[":
                stack.append("]")
            elif item == "{":
                stack.append("}")
            elif not stack or item!=stack[-1]: # 如果栈提前变空或者栈顶元素和字符串元素不匹配
                return False 
            else: # 如果栈顶元素和字符串相同,直接pop掉栈顶元素
                stack.pop() 
        return not stack # 最后如果遍历完字符串,栈内为空,说明匹配成功

3. 复杂度分析

时间复杂度:O(N)

字符串长度为N,里面的元素需要都遍历一遍,因此时间复杂度为O(N);

空间复杂度:O(N)

需要一个栈来储存元素,大小是O(N)级别的,总体来说的空间复杂度也为O(N)。


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

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

  1. 思路

这个题就是有效的括号变题,感觉不用多讲了吧。如果栈不为空,同时栈顶元素和字符串当前元素相同,那么直接把栈顶元素弹出,否则就不停的往站内append元素即可。这个题和google面试的 decode string题目异曲同工!

2.代码

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

3.思考

栈适合用来解决匹配的问题

谷歌面试有什么陨石碰撞,石头重量相同就粉碎这种,其实本质上就是栈的匹配问题。


重新回来刷题的思考:2023年2月13号。

行百里者半九十,没想到自己竟然也成为了茫茫大军中放弃的一个人。归根结底还是因为1月13号收到谷歌实习面试的拒信那天,给了我挺大的心理打击。从那天之后,我就没有碰过leetcode,没有认真刷题,在这一个月里,天天幻想着能够有白马王子来解决自己的身份问题。但我从来就知道,最稳的方法从来就是自己要变强,求别人的永远都会内心不安,从而也不曾得到。靠我投机取巧得来的面试机会,也靠着我的实力不足给完美的错过了。如果说去年面试大厂实习全军覆没是因为自己实力不足,project根本没有做,题目也没有吃透,面试的时候紧张。那么说今年能不能在未知的情况下尽可能把自己这边先做好,问心无愧,再去抱怨说生活的苦,我觉得这是我这个spring学期所要面对的功课。我要恭喜自己,终于分手成功,离开了一个并不适合自己的人。女生还是要学会独立。要学会开车。当年感觉学gre很累,很辛苦,但其实每天安排一点点学习时间,学出来也就是3个月的时间,真的没有很久。我觉得自己也应该要对自己的人生负责,不要想着什么男人,不要想着什么婚姻绿卡,把自己的实力真真正正的提高,不要投机取巧的方式,才是最快的提高方法。加油吧,日子还很长。努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值