剑指offer(python)-栈和队列

01-用两个栈实现队列

题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
复习:
栈的特性:先进后出
在这里插入图片描述
队列的特性:先进先出
在这里插入图片描述
思路:

解析:使用两个栈来实现一个队列,其实就是组合两个栈,来实现队列,栈是先进后出,队列是先进先出,可使用以下操作使用栈来实现队列:

一、入队列:
把需要存放的元素插入到栈1中
在这里插入图片描述
二、出队列:

**ps:此时栈顶元素就是需要出队列的元素
入栈时数据存入栈stackIn, 出栈时数据从stackOut弹出。执行入栈操作时,将数据源源不断的压入栈stackIn;执行出栈操作时,将stackIn的数据一次性全部弹出,存入到stackOut中。当stackOut栈非空时,不断弹出stackOut栈中的数据顺序即为队列的Pop顺序;当stackOut中的数据为空后,再将新入栈stackIn的数据一次性存入stackOut中即可。相比于上一种方式,这种方式极大降低了数据在栈stackIn和栈stackOut中来回无意义的腾挪操作,占据更低的存储空间,消耗更低的运算时间。

class Solution:
    def __init__(self):
        self.stackIn = []
        self.stackOut = []

    def push(self, node):
        self.stackIn.append(node)

    def pop(self):
        if not self.stackOut:
            while self.stackIn:
                self.stackOut.append(self.stackIn.pop(-1))
        return self.stackOut.pop(-1)  #(-1)代表从顶部pop


# 实例化
if __name__=='__main__':
    node=[1,2,4,7,3,5,6,8]
    demo = Solution()
    print(demo.push(node),demo.pop())

02-包含min函数的栈,栈的压入弹出

题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))

思路:链接: 看到这个问题, 我们最开始可能会想, 添加一个成员变量用于保存最小元素, 每次压栈时如果压栈元素比当前最小元素更小,
就更新最小元素.
但是这样会有一个问题, 如果最小元素被弹出了呢, 如何获得下一个最小元素呢? 分析到这里可以发现, 仅仅添加一个成员变量存放最小元素是不够的, 我们需要在最小元素弹出后还能得到次小元素, 次小的弹出后, 还要能得到次次小的.
因此, 用另一个栈来保存这些元素是再合适不过的了. 我们叫它最小元素栈.
每次压栈操作时, 如果压栈元素比当前最小元素更小, 就把这个元素压入最小元素栈, 原本的最小元素就成了次小元素. 同理, 弹栈时, 如果弹出的元素和最小元素栈的栈顶元素相等, 就把最小元素的栈顶弹出.

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.arr=[]
    def push(self, node):
        # write code here
        self.arr.append(node)
    def pop(self):
        # write code here
        return self.arr.pop()
    def top(self):
        return self.arr[-1]
    def min(self):
        # write code here
        return min(self.arr)

21,题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路

栈的压入顺序是指1,2,3,4,5是依次push到栈的,但并不是说只有push的过程,也可能有pop的操作,比如push
1,2,3,4之后,把4pop出去,然后再push5,也是一样的压入顺序;弹出序列是指每次pop出去的元素都是当时栈顶的元素,比如一开始pop1,2,3,4,然后pop4,再push5,再pop5,然后依次pop3,2,1,那么弹出序列就是4,5,3,2,1;

那么就可以构造一个辅助栈来判断弹出序列是不是和压栈序列对应。首先遍历压栈序列的元素push到辅助栈,判断是不是弹出序列的首元素,如果是,则弹出序列pop首元素(指针后移),如果不是,则继续push,再接着判断;直到遍历完了压栈序列,如果辅助栈或者弹出序列为空,则返回True,否则返回False
**

总的来说,判断一个序列是不是栈的弹出序列,主要把握一个规律:
如果下一个弹出的数字刚好是栈顶数字,那么直接弹出;
如果下一个弹出的数字不在栈顶,我们就要把压栈序列中还没有入栈的数字压入辅助栈,
直到把下一个需要弹出的数字压入栈顶为止;
如果所有的数字都压入了栈中仍然没有找到下一个弹出的数字,那么该序列就不可能是一个合法的弹出序列
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190222142404477.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI0NDI5MzMz,size_16,color_FFFFFF,t_70)
思路:利用一个辅助栈来存放最小值

栈  3,4,2,5,1
辅助栈 3,3,2,2,1

每入栈一次,就与辅助栈顶比较大小,如果小就入栈,如果大就入栈当前的辅助栈顶
当出栈时,辅助栈也要出栈
这种做法可以保证辅助栈顶一定都当前栈的最小值

实例化
链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
来源:牛客网

【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:

入栈1,2,3,4,5

出栈4,5,3,2,1

首先1入辅助栈,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。

**
#如果stack的最后一个元素与popV中第一个元素相等,将两个元素都弹出

class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        if not pushV or len(pushV)!=len(popV): # 如果数据长度不等返回0
            return 0
        stack = []  # 定义辅助栈
        for v in pushV:
            stack.append(v) #把压栈顺序的添加到辅助栈中
            while len(stack) and stack[-1]==popV[0]: #辅助栈不为空当辅助栈不为空且栈顶元素等于弹出元素时
                stack.pop()
                popV.pop(0)
        if len(stack):
            return 0
        return 1

stack【-1】栈里 栈顶的值是存在val[- 1]里,popV 是序列,它与数组元素的对应关系,应该是 val[0]是第1个元素.

# -*- coding:utf-8 -*-
class Solution:
 
    def IsPopOrder(self, pushV, popV):
        # stack中存入pushV中取出的数据
        stack=[]
        while popV:
            # 如果第一个元素相等,直接都弹出,根本不用压入stack
            if pushV and popV[0]==pushV[0]:
                popV.pop(0)
                pushV.pop(0)
            #如果stack的最后一个元素与popV中第一个元素相等,将两个元素都弹出
            elif stack and stack[-1]==popV[0]:
                stack.pop()
                popV.pop(0)
            # 如果pushV中有数据,压入stack
            elif pushV:
                stack.append(pushV.pop(0))
            # 上面情况都不满足,直接返回false。
            else:
                return False
        return True

思路2“这个可考虑”
解题思路:当前出栈为a,则下一个出栈的数字在入栈序列中,可以是排在它后面的任意一项,也可以是他前面的项,但跟她的索引值之差不能大于1.需要注意的是它也可能不在原来的序列中,所以要先判断它是否存在,在用.index函数找索引

  # -*- coding:utf-8 -*-
    
    class Solution:
        def IsPopOrder(self, pushV, popV):
            # write code here
            list_len = len(pushV)
            for i in range(len(popV)):
                pop_num = popV.pop(0)
                if pushV.count(pop_num):
                    
                    index = pushV.index(pop_num)
                    if popV:
                        if pushV[index:len(pushV)].count(popV[0]) or (pushV[0:index].count(popV[0]) and abs(pushV[0:index].index(popV[0])- index)==1):
                            pushV.pop(index)
                        else:
                            return False
                    else:
                        return True
                else:
                    return False

原文:https://blog.csdn.net/Jillian_sea/article/details/80339471

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值