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

80 阅读3分钟

栈和队列的理论基础

232. 用栈实现队列

链接

文章链接

题目链接

第一想法

因为只能用那几种方法,所以只能模拟了,想法是准备两个栈a和b,当执行pop和peek时先将原本的存储栈a通过pop导入b,此时b的top就是所需元素,代码如下:

class MyQueue {
  arr:number[]
  list:number[]
  constructor() {
   this.list =[]
   this.arr=[]
  }

  push(x: number): void {
   this.list.push(x)
  }

  pop(): number {
      for(let i=this.list.length-1;i>=0;i--){
          this.arr.push(this.list.pop() as number)
      }
      let num:number=this.arr.pop() as number
      for(let i=this.arr.length-1;i>=0;i--){
          this.list.push(this.arr.pop() as number)
      }
      return num
  }

  peek(): number {
      for(let i=this.list.length-1;i>=0;i--){
          this.arr.push(this.list.pop() as number)
      }
      let num:number=this.arr.pop() as number
      this.list.push(num)
      for(let i=this.arr.length-1;i>=0;i--){
          this.list.push(this.arr.pop() as number)
      }
      return num
  }

  empty(): boolean {
   return this.list.length==0
  }
}

看完文章后的想法

文章的想法比我的全面和详细,我pop之后还会把b导入a,其实是完全不用的,因为b导入a并不会影响pop和peek,而且代码是可以复用的,所以不用写那么多重复代码。代码如下:

class MyQueue {
    stdIn:number[] //用于模拟入栈
    stdOut:number[] //用于模拟出栈
    constructor() {
     this.stdIn =[]
     this.stdOut=[]
    }

    push(x: number): void {
     this.stdIn.push(x)
    }

    pop(): number {
        if(this.stdOut.length===0){ //当出栈里没有元素时再从入栈导入
            while(this.stdIn.length!=0){
                this.stdOut.push(this.stdIn.pop())
            }
        }
        return this.stdOut.pop()
    }

    peek(): number {
      let num:number=this.pop() //调用刚刚的pop方法
      this.stdOut.push(num)
     return num
    }

    empty(): boolean {
     return this.stdIn.length==0&&this.stdOut.length==0
    }
}

下面附代码随想录里面的图帮助理解: 代码随想录

思考

用栈模拟队列,要理解栈和队列的区别,一个先进先出(queue),一个后进先出(stack),所以要用栈模拟队列,一定要有两个栈,一个模拟入栈,一个模拟出栈。总体上不难,但是要把细节想好不容易。

225. 用队列实现栈

链接

文章链接

题目链接

第一想法

这一道题是用队列模拟栈,队列先进先出,栈后进先出,这道题和栈模拟队列是不一样的,队列既可以进入又可以出去,所以只需要一个队列queue就行了

class MyStack {
  queue:number[]
  constructor() {
   this.queue=[]
  }

  push(x: number): void {
   this.queue.push(x)
  }

  pop(): number {
     let len:number=this.queue.length-1 //pop将要出去的元素再填入队列中
     while(len>0){
         this.queue.push(this.queue.shift() as number) //出去再进来
         len--
     }
     return this.queue.shift() as number //最后一个元素只出不进
  }

  top(): number {
  //和栈模拟队列一样
     let num:number=this.pop()
     this.queue.push(num)
     return num
  }

  empty(): boolean {
   return this.queue.length===0
  }
}

看完文章后的想法

我的想法和代码随想录中优化完的思路是一致的,同时代码随想录中也有使用了两个队列完成栈的任务,于是乎我也写了一遍:

class MyStack {
  queue:number[]
  queue2:number[]
  constructor() {
   this.queue=[]
   this.queue2=[]
  }

  push(x: number): void {
   this.queue.push(x)
  }

  pop(): number {
     while(this.queue.length!=1){
         this.queue2.push(this.queue.shift() as number)
     }
     let num:number=this.queue.shift() as number
     this.queue=this.queue2
     this.queue2=[]
     return num
  }

  top(): number {
     let num:number=this.pop()
     this.push(num)
     return num
  }

  empty(): boolean {
   return this.queue.length===0
  }
}

下面是代码随想录中的模拟的gif图片 代码随想录

思考

这道题不难,用一个队列或两个队列都可以解决这个问题,同时也要理解先进先出和后进后出的区别,仔细看完文章后会有很深的感触。

今日总结

今天的题就两道,不算太难,但是要理解栈stack的后进先出和队列queue的先进先出的真正含义,这两道题的理论意义大于实践意义,要明白其中的原理。同时学到了一种写代码的习惯,减少重复代码(封装函数等方法)。