代码随想录算法训练营第十天| 232. 用栈实现队列、225. 用队列实现栈

定义

栈实现数据的后进先出(LIFO

这边用列表的方式构造栈

ps:python3版本默认加载了object了(即使没有写上object),所以python3版本在写类的时候加不加object没有区别。

class Stack: 
    """栈"""
    def __init__(self):
         self.items = []

    def is_empty(self):
        """判断是否为空"""
        return self.items == []

    def push(self, item):
        """加入元素"""
        self.items.append(item)

    def pop(self):
        """弹出元素"""
        return self.items.pop()

    def peek(self):
        """返回栈顶元素"""
        return self.items[len(self.items)-1] # 就是返回最后一个元素

    def size(self):
        """返回栈的大小"""
        return len(self.items)

if __name__ == "__main__":
    stack = Stack()
    stack.push("hello")
    stack.push("world")
    stack.push("itcast")
    print stack.size()
    print stack.peek()
    print stack.pop()
    print stack.pop()
    print stack.pop()
  • pop()方法用于删除列表中的最后一个元素,并返回该元素本身

  • 也可通过下标(从0开始)指定删除某个元素

a=[1,2,3,4,5]
a.pop() # 5
a # [1,2,3,4]
  • pop()只有一个参数位
队列
class Queue(object):
    """队列"""
    def __init__(self):
        self.items = []

    def is_empty(self):
        return self.items == []

    def enqueue(self, item):
        """进队列"""
        self.items.insert(0,item)

    def dequeue(self):
        """出队列"""
        return self.items.pop()

    def size(self):
        """返回大小"""
        return len(self.items)

if __name__ == "__main__":
    q = Queue()
    q.enqueue("hello") 
    q.enqueue("world")
    q.enqueue("itcast")
    print q.size()
    print q.dequeue()
    print q.dequeue()
    print q.dequeue()

  • list. insert(index, obj)。其中index 是对象 obj 需要插入的索引位置,obj是要插入列表中的对象。
vowel = ['a', 'e', 'i', 'u']
vowel.insert(3, 'o')
print('更新列表: ', vowel)
# 更新列表: ['a', 'e', 'i', 'o', 'u']

其中insert索引的位置如下

232. 用栈实现队列

题目链接:232. 用栈实现队列

思路

首先想到的是,比较形象地描述:队列是“双开口”的,栈是“单开口”的。如果想要用栈实现队列自然需要两个栈。
而如何将两个栈“连”起来,则比较麻烦。下面画了简单的原理图:
在这里插入图片描述
利用python里面常用的.append()和.pop()函数可以实现“入栈”和“出栈”的操作。
Ps:关键是要有栈的一些限制,必须是“后进先出”。不能用一些函数直接把最开始的数取出来了。

代码
class MyQueue:

    def __init__(self):
        """
        in用于push,out用于破pop
        """
        self.stack_in = []
        self.stack_out = []

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

    def pop(self) -> int:
        if self.empty(): # 两个栈为空则不再输出
            return None

        if self.stack_out:
            return self.stack_out.pop()
        else:
            while len(self.stack_in)>0:
                self.stack_out.append(self.stack_in.pop())
            return self.stack_out.pop()

    def peek(self) -> int:
        ans = self.pop()
        self.stack_out.append(ans)
        return ans

    def empty(self) -> bool:
        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()
反思

1、pop为什么要考虑stack_out是否为空?

 def pop(self) -> int:
     if self.empty(): # 两个栈为空则不再输出
         return None

     if self.stack_out:
         return self.stack_out.pop()
     else
         while len(self.stack_in)>0:
             self.stack_out.append(self.stack_in.pop())
         return self.stack_out.pop()

当stack_out为空时,会将stack_in的所有元素放进stack_out才能获得队头元素,但取出队头元素后, stack_out中还会有剩余的元素。下次取队头元素,只需要从stack_out中pop()就可以。

在这里插入图片描述
2.peek为什么需要把元素取出来再放进stack_out?

def peek(self) -> int:
    ans = self.pop()
    self.stack_out.append(ans)
    return ans

考虑到上面取出时的三种情况,因此直接用pop取出队头元素,会避免很多麻烦。

3.如何写empty函数比较简洁?
一开始我自己写的如下

def empty(self) -> bool:
    if len(self.stack_in)+len(self.stack_out)==0:
        return True
    else:
        return False

后来看了答案,发现答案写的更简洁

def empty(self) -> bool:
    return not (self.stack_in or self.stack_out)

数组也是可以用or来判断是否为空的。
两个数组只要有一个不是空的则返回False。

知识点回顾

1、python删除函数回顾

  • remove()
  • pop()
  • del()
  1. remove()函数
    remove() 函数可以删除列表中的指定元素,且一次只能删除一个元素。
a=[1,2,3,2]
a.remove(2)
print(a)
#输出:[1,3,2]
  1. pop()函数
    pop() 函数用于随机移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
fruits = {'apple','banana','cherry'}
x = fruits.pop()
print(x)
print(fruits)
#输出:
#banana
#{'cherry', 'apple'}

pop()也可用于删除指定下标的数组元素(下标从0开始)

a=[1,2,3,2]
x=a.pop(1)
print(x)
print(a)
#输出:
#2
#[1,3,2]
  1. del()函数
    del删除的是变量,而不是数据
li=[1,2,3,4,5]  #列表本身不包含数据1,2,3,4,5,而是包含变量:li[0] li[1] li[2] li[3] li[4]   
first=li[0]     #拷贝列表,也不会有数据对象的复制,而是创建新的变量引用  
del li[0]  
print(li)      #输出[2, 3, 4, 5]  
print(first)   #输出 1  

225. 用队列实现栈

题目链接:225. 用队列实现栈
用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用

一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。

思路一

两个队列,队列1用来存储,队列2用来pop。
当需要pop时, 用将队列1前n-1个元素放入队列2,此时队列1只剩下一个栈顶元素。然后交换队列1和队列2,从队列2取出元素,即为栈顶元素

代码一
class MyStack:

    def __init__(self):
         self.queue_in=deque() # 存数据使用
         self.queue_out=deque() # 仅在pop时使用

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

    def pop(self) -> int:
        if self.empty():
            return None
        for i in range(len(self.queue_in)-1):
            self.queue_out.append(self.queue_in.popleft())
        
        self.queue_in, self.queue_out = self.queue_out, self.queue_in #所以说out只是用来存储的
        return self.queue_out.popleft()

    def top(self) -> int:                                    
        ans = self.pop()
        self.queue_in.append(ans)
        return ans

    def empty(self) -> bool:
        return len(self.queue_in)==0
思路二

只用一个队列。一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。

class MyStack:

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

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

    def pop(self) -> int:
        if self.empty():
            return None
        for i in range(len(self.queue)-1):
            self.queue.append(self.queue.popleft())
        return self.queue.popleft()

    def top(self) -> int:                                    
        ans = self.pop()
        self.queue.append(ans)
        return ans

    def empty(self) -> bool:
        return len(self.queue)==0
知识点回顾

1、collections模块中的deque双端队列结构
deque 是 double-ended queue的缩写,类似于 list,不过提供了在两端插入和删除的操作。

  • appendleft 在列表左侧插入
  • popleft 弹出列表左侧的值
  • extendleft 在左侧扩展
#-*- coding: UTF-8 -*-
from collections import deque                                               

# mydeque =deque() 创建一个普通队列

#  可以指定 队列的长度
mydeque=deque(maxlen=10)
print(mydeque.maxlen) # 10

# 默认从右边加入
mydeque.append(10)
mydeque.append(12)
print(mydeque) # deque([10, 12])

# 也可以从左边加入
mydeque.appendleft('a')
mydeque.appendleft('b')
print(mydeque) # deque(['b', 'a', 10, 12])

mylist= range(5,7)
# 也可以加入一个列表,默认从右边加入
# mydeque.extend(mylist)
mydeque.extendleft(mylist) # 从左边扩展
print(mydeque) # deque([6, 5,'b', 'a', 10, 12])

# 出队列,返回出队列的元素 
# 可以从左边也可以从右边 出队列 
mydeque.pop() # 12
mydeque.popleft() # 6

# 查看 队列里面元素个数
print(len(mydeque)) # 4

# 统计元素的个数
#统计a 有几个
print(mydeque.count('a')) # 1

# 在某个位置insert 一个元素 
# insert(i, x)
# Insert x into the deque at position i.
mydeque.insert(3,'frank')
print(mydeque) # deque([6, 5,'b', 'frank','a', 10, 12])

#翻转操作
mydeque.reverse()
print(mydeque) # deque([12,10,'a','frank','b',5,6])

# remove 移除某个元素 
mydeque.remove('frank')
print(mydeque) # deque([12,10,'a','b',5,6])

# 清空队列元素 clear
mydeque.clear()
print(mydeque) # deque([])

rotate 方法:

value 是步长,rotate(value) 对队列实行旋转操作(每个元素依次向后移动value步,最后一个移动到第一个算一步)

from collections import deque
d = deque()
d.extend(['a', 'b', 'c', 'd', 'e'])
d.rotate(2)  # 指定次数,默认1次
print(d) # deque(['d', 'e', 'a', 'b', 'c'])

maxlen 说明

  • 如果构建deque 的时候,指定了maxlen, 则可以通过 d.maxlen 来获得dueue的最大长度.
  • 如果插入的数据大于 maxlen 则会自动删除旧的元素.
  • 删除 什么元素,取决于, 从哪边添加数据.
d = deque(list(range(5)),maxlen=5)
d
Out[21]: deque([0, 1, 2, 3, 4])

d.maxlen
Out[26]: 5

# 从左边添加元素, # 元素4 被挤出 队列

d.appendleft('frank')
d
Out[23]: deque(['frank', 0, 1, 2, 3])

# 从右边添加元素, 元素 'frank'  被挤出队列.
d
Out[23]: deque(['frank', 0, 1, 2, 3])
d.append('xiaoming')
d
Out[25]: deque([0, 1, 2, 3, 'xiaoming'])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值