从零学算法

232.请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

  • 我的思路比较蠢,用两个栈,第一个栈 A 就正常 push,等于逆序存储了队列的值,在 push 或 peek 时,把栈 A 的值 pop 并 push 到另一个栈 B,栈 B 存储的就是正确顺序的队列的值,pop 或 peek 完了之后再把 B 的 pop 回 A。
  •   class MyQueue {
          Stack<Integer> stack = new Stack<>();
          Stack<Integer> queue = new Stack<>();
      
          public MyQueue() {
      
          }
          
          public void push(int x) {
              stack.push(x);
          }
          
          public int pop() {
              while(!stack.isEmpty()){
                  queue.push(stack.pop());
              }
              int val =  queue.pop();
              while(!queue.isEmpty()){
                  stack.push(queue.pop());
              }
              return val;
          }
          
          public int peek() {
              while(!stack.isEmpty()){
                  queue.push(stack.pop());
              }
              int val = queue.peek();
              while(!queue.isEmpty()){
                  stack.push(queue.pop());
              }
              return val;
          }
          
          public boolean empty() {
              return stack.isEmpty();
          }
      }
    
  • 但是如果连续多次 pop 或 peek 时,其实我们不需要每次都把数据来回倒腾一遍,定义一个布尔值记录当前是否是顺序存储,pop 或 peek 如果不为顺序就搞成顺序,否则直接 pop 或 peek 即可,push 时如果为顺序就再倒腾回来,否则直接 push。
  •   class MyQueue {
          Stack<Integer> stack = new Stack<>();
          Stack<Integer> queue = new Stack<>();
          boolean isAsc;
      
          public MyQueue() {
      
          }
          
          public void push(int x) {
              if(isAsc){
                  isAsc = false;
                  while(!queue.isEmpty()){
                      stack.push(queue.pop());
                  }
              }
              stack.push(x);
          }
          
          public int pop() {
              if(isAsc){
                  return queue.pop();
              }
              isAsc = true;
              while(!stack.isEmpty()){
                  queue.push(stack.pop());
              }
              return  queue.pop();
          }
          
          public int peek() {
              if(isAsc){
                  return queue.peek();
              }
              isAsc = true;
              while(!stack.isEmpty()){
                  queue.push(stack.pop());
              }
              return queue.peek();
          }
          
          public boolean empty() {
              return stack.isEmpty() && queue.isEmpty();
          }
      }
    

+在上面我之所以一旦在 pop 或 peek 操作后再 push,就要把元素重新从 queue pop 回 stack,就是为了保持 stack 的倒序存储,保证了 stack 的倒序,在需要 pop 或 peek 就能重新 pop 回 queue,保证了 queue 的顺序存储。但是实际上不需要这么复杂,当遇到 pop 或 peek 操作时,只要 queue 为空就把 stack 的元素都 pop 到 queue,当 push 时就只需要正常 push 到 stack 即可,这样的话当你 pop 或 peek 时,你只有把之前顺序存储的元素用完了才会再从 stack 取元素。用完了才再填充这一件事,就是保持 stack 和 queue 按照正确顺序存储元素的关键。比如正常入队元素为 [1,2,3],stack 在 push 完 [1,2] 后为 [2,1],这时我 pop,queue 就开始填充为 [1,2],然后 pop 出 1 剩余 [2],stack 此时为 [],如果我 push 完 3 后再 pop,直接就再把 3 填充到 queue 的 [2],就成了[3,2] 然后 pop queue 的 3,实际上应该 pop 2 才对,而我把 queue 用完上一轮正确存储的元素再存储后就保证了使用 queue 的元素时,顺序都是正确的,也就是先 pop 了 1, 然后 pop 2,等到没东西 pop 了才把 stack 的 3 拿过来 pop。

  •   Stack<Integer> stack = new Stack<>();
      Stack<Integer> queue = new Stack<>();
    
      public MyQueue() {
    
      }
      
      public void push(int x) {
          stack.push(x);
      }
      
      public int pop() {
          fillQueue();
          return  queue.pop();
      }
      
      public int peek() {
          fillQueue();
          return queue.peek();
      }
      
      public boolean empty() {
          return stack.isEmpty() && queue.isEmpty();
      }
    
      public void fillQueue(){
          if(queue.isEmpty()){
              while(!stack.isEmpty()){
                  queue.push(stack.pop());
              }
          }
      }
    

你可能感兴趣的:(算法学习,#,栈,算法,java,python)