代码随想录算法训练营第11日| 栈与队列 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

理论基础(摘自代码随想录)

 

栈和队列是STL(C++标准库)里面的两个数据结构。

C++标准库是有多个版本的,要知道我们使用的STL是哪个版本,才能知道对应的栈和队列的实现原理。

那么来介绍一下,三个最为普遍的STL版本:

  1. HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。

  2. P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。

  3. SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。

接下来介绍的栈和队列也是SGI STL里面的数据结构, 知道了使用版本,才知道对应的底层实现。

来说一说栈,栈先进后出,如图所示:栈与队列理论2

 栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。

栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。

所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。

那么问题来了,STL 中栈是用什么容器实现的?

从下图中可以看出,栈的内部结构,栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。

栈与队列理论3

我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的低层结构。

deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了。

SGI STL中 队列底层实现缺省情况下一样使用deque实现的。

我们也可以指定vector为栈的底层实现,初始化语句如下:

std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈

刚刚讲过栈的特性,对应的队列的情况是一样的。

队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。

也可以指定list 为起底层实现,初始化queue的语句如下:

std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列

所以STL 队列也不被归类为容器,而被归类为container adapter( 容器适配器)。

232.用栈实现队列

python 中可以直接用list来模拟栈stack, list可以用pop() 和 append()来模拟出栈入栈

这道题用栈实现队列, 栈是先入后出, 队列是先入先出的,思路就可以用两个栈stack_in来实现push,然后再把stack_in中的元素加进第二个栈stack_out中,stack_out就负责出栈。只要stack_in和stack_out不为空,那么整个模拟的队列就不为空

push函数:只要有新元素进来,就往stack_in中加

pop函数:如果模拟的队列是空的,return None; 如果stack_out是空的,就把stack_in的元素往里pop,然后stack_out pop, 如果stack_out有元素就pop

peek函数:找队首元素,其实就是找stack_out中的元素,可以直接调用pop函数,但是要记得补上

class MyQueue:

    def __init__(self):
        """
        in主要负责push,out主要负责pop
        """
        self.stack_in = []
        self.stack_out = []


    def push(self, x: int) -> None:
        """
        有新元素进来,就往in里面push
        """
        self.stack_in.append(x)


    def pop(self) -> int:
        """
        Removes the element from in front of queue and returns that element.
        """
        if self.empty():
            return None
        
        if self.stack_out:
            return self.stack_out.pop()
        else:
            for i in range(len(self.stack_in)):
                self.stack_out.append(self.stack_in.pop())
            return self.stack_out.pop()


    def peek(self) -> int:
        """
        Get the front element.
        """
        ans = self.pop()
        self.stack_out.append(ans)
        return ans


    def empty(self) -> bool:
        """
        只要in或者out有元素,说明队列不为空
        """
        return not (self.stack_in or self.stack_out)



# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()

225. 用队列实现栈 

用一个队列模拟栈,在python中可以用双向队列deque()

push就是正常加进队列

pop 就是把队列的前n-1个元素弹出,然后加进队尾,再弹出就是栈的出栈顺序了

class MyStack:

    def __init__(self):
        self.queue = deque()


    def push(self, x: int) -> None:
        self.queue.append(x)


    def pop(self) -> int:
        if not self.queue: return None
        for i in range(len(self.queue)-1):  #把队列前n-1个元素弹出来再加到队尾(右)
            self.queue.append(self.queue.popleft()) 
        return self.queue.popleft()        #然后再popleft就和栈的弹出顺序一样了


    def top(self) -> int:
        return self.queue[-1]   #栈顶的话 对应的应该是最后进来的那个元素,先入后出嘛,在队列里就是队尾(右边)


    def empty(self) -> bool:
        return not self.queue

20. 有效的括号 

这道题是用栈的

这里有三种不匹配的情况,

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

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

第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false |   

第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false  |   

第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。

如下图代码所示:

在遍历的过程中,我们遇到左括号,就把对应的右括号放入栈中

然后遍历到右括号的时候,如果说栈不为空,并且栈顶元素等于此时遍历的元素,说明配对了,消消乐

else省略的条件是什么呢?是栈为空,代表右括号多,或者stack栈顶元素不匹配,return False

class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        for item in s:
            if item == '(': stack.append(')')
            elif item == '[': stack.append(']')
            elif item == '{': stack.append('}')
            elif stack and stack[-1] == item:
                stack.pop()
            else:
                return False
        return not stack
class Solution:
    def isValid(self, s: str) -> bool:
        dic = {'(':')','[':']','{':'}'}
        stack = []
        for ch in s:
            if ch in dic.keys():
                stack.append(dic[ch])
            elif stack and ch == stack[-1]:
                stack.pop()
            else:
                return False
        return not stack
        

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

这个题的拿栈去做的思想,类似于加入的元素如果等于栈顶就可以消消乐的感觉

就是拿一个list去模拟栈,然后在遍历s的时候,如果栈为空或者栈顶元素不等于当前遍历到的元素,就把该元素入栈,如果栈不为空并且栈顶元素等于遍历到的当前元素的话,就出栈消消乐

注意,在拿list去模拟的时候,要注意哪里是头哪里是尾,list的pop是pop的尾部,添加的元素也是从尾部添加的。最后返回出list其实就是题要求的结果

def removeDuplicates(self, s: str) -> str:
        stack = []
        for i in s:
            if not stack or stack[-1] != i:
                stack.append(i)
            else:
                stack.pop()
        return ''.join(stack)
def removeDuplicates(self, s: str) -> str:
        stack = []
        for i in s:
            if stack and stack[-1] == i:
                stack.pop()
            else:
                stack.append(i)
        return ''.join(stack)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值