【剑指Offer】5、用两个栈实现队列

本文探讨如何使用两个栈实现队列的Push和Pop操作,以达到队列的先进先出特性。通过分析错误版本和优化版本,揭示了在实现过程中需要注意的细节和巧妙构思,强调了学习他人优秀源码对于提升编程技能的重要性。
摘要由CSDN通过智能技术生成

一、题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

例如:

# Input
["PSH1","PSH2","PSH3","POP","POP","PSH4","POP","PSH5","POP","POP"]
# Ouput
1,2,3,4,5

二、代码

思路:这道题稍微需要思考一下,需要想想如何利用两个堆栈(先进后出–FILO)来达到队列先进先出–FIFO的特性。

版本1.0(错误)

其中一个方案,步骤如下:V1
S1:将节点加入stack1,在此实现push(int node);
S2:将stack1的节点放入stack2.在此把顺序倒过来,先入后出*2 ==> 先入先出。然后pop();
问题:但针对这里得保证先全部push(),然后全部pop(),否则丢出的节点很可能就不满足队列特性了。

// 下面代码无法通过,可自己动手试试上面的例子。
import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.add(node);
    }
    
    public int pop() {
    	int tmp;
    	while(!stack1.empty()) {
    		stack2.add(stack1.pop());
    	}
    	tmp = stack2.pop();
    	return tmp;
    }
}
版本1.5:My

思路:改良上面步骤 V1.5
S1:将stack2全部节点先倒入stack1,然后再放节点;
S2:不变同上。

import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        while(!stack2.empty()) {
    		stack1.add(stack2.pop());
    	}
        stack1.add(node);
    }
    
    public int pop() {
    	int tmp;
    	while(!stack1.empty()) {
    		stack2.add(stack1.pop());
    	}
    	tmp = stack2.pop();
    	return tmp;
    }
}
版本2:参考 ProJay

问题:上面代码显得不太清晰,起始过程容易被搞蒙。所以将stack2的节点再放入stack1放到pop()中。步骤如下:V2
S1:将节点加入stack1,在此实现push(int node);
S2:将stack1的节点放入stack2.在此把顺序倒过来,先入后出*2 ==> 先入先出。为保证下一步stack1()的push(int node)是按顺序的,再把节点从stack2倒回stack1中。然后pop();

import java.util.Stack;
 
public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
     
   public void push(int node) {
        stack1.push(node);
    }
   
   public int pop() {
        
       while(!stack2.isEmpty())
        {
            return stack2.pop();
        }
         
        while(!stack1.isEmpty())
        {
            stack2.push(stack1.pop());
        }
        
        return stack2.pop();
    }
}
版本3:参考侯夏冰(左程云《程序员代码面试指南》)

问题:上面的代码需要在stack1与stack2来回导,这来回导的操作其实可以省略。
步骤如下:V3
S1:不变同上。
S2:pop()时判断一些stack2是否为空,空则从stack1导入stack2,否则暂时存放在stack1中。

import java.util.Stack;
 
public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
     
    public void push(int node) {
        stack1.push(node);
    }
     
    public int pop() {
        if(stack1.empty()&&stack2.empty()){
            throw new RuntimeException("Queue is empty!");
        }
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

完整简单测试小程序:

import java.util.Stack;
import java.util.Scanner;

class Solution {
	
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.add(node);
    }
    public int pop() {

    	if(stack2.empty()) {
    		while(!stack1.empty()) {
        		stack2.add(stack1.pop());
        	}    		
    	}

    	return stack2.pop();
    }
}

public class Main {

	public static void main(String[] args) {
		
		int num, tmp, cnt=0;
		
		Solution solu = new Solution();
		Scanner input = new Scanner(System.in);
		
		num = input.nextInt();
		while(num!=-1) {
			cnt++;
			solu.push(num);	
			num = input.nextInt();
		}		
		for(int i=cnt;i>0;i--) {			
			tmp = solu.pop();
			System.out.print(tmp + " ");
		}

	}

}
# Input
1 2 3 -1
# Output
1 2 3 

三、小结

从这几个版本可以看到有时候一个小小的题目都可以充满各种小小的精巧的构思。这里面有些东西往往是你没看过就可能真的永远想不到,所以多看一些别人优秀的源码非常有必要,这是提高自己程序素养的必要手段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值