九度OJ-题目1512:用两个栈实现队列

题目链接地址:

九度OJ-题目1512:用两个栈实现队列


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

输入:
每个输入文件包含一个测试样例。
对于每个测试样例,第一行输入一个n(1<=n<=100000),代表队列操作的个数。
接下来的n行,每行输入一个队列操作:
1. PUSH X 向队列中push一个整数x(x>=0)
2. POP 从队列中pop一个数。

输出:
对应每个测试案例,打印所有pop操作中从队列pop中的数字。如果执行pop操作时,队列为空,则打印-1。

样例输入:
3
PUSH 10
POP
POP

样例输出:
10
-1


解题思路:

用两个栈来实现一个队列,完成队列的Push和Pop操作。刚开始看到这道题的时候,我的想法是先开两个栈s1和s2,s1用来存放入队操作Push所对应的元素,s2用来存放出队操作Pop所对应的元素。如果遇到Push操作,先判断s2中是否有元素,如果s2中有元素,就将s2栈中的元素全部倒入到s1栈中,再将入队元素插入到s1的栈顶;如果遇到Pop操作,就先将s1栈中的元素全部倒入到s2栈中,然后再弹出s2栈的栈顶元素。简单来说,就是开两个栈,然后将这两个栈中的元素“倒来倒去”以实现队列的Push和Pop操作。但是这种算法TLE了 囧 。。。
后来和范神讨论,范神给了我一个巧妙的算法,避免了“倒来倒去”的过程。这个算法大概思想是开两个栈s1和s2,如果遇到Push操作则直接将入队元素压入到s1栈中;如果遇到Pop操作则直接弹出s2栈的栈顶元素(只有当s2栈为空时,才将s1中的元素压入到s2中,这样就避免了“倒来倒去”的现象)。这种算法的本质就是s1栈从栈底到栈顶依次保存队列的后半段,s2栈从栈顶到栈底依次保存队列的前半段。请脑补这样的画面:s1栈的栈底与s2的栈底连在了一起,然后都横着摆放共同组成了一个队列。

具体的样子请看图1:

九度OJ-题目1512:用两个栈实现队列_第1张图片

图1 s1栈和s2栈拼接形成的队列

如果连续执行Pop操作弹出元素1,2,3,4,栈s2将变成空栈,
如图2所示:

图2 s2栈为空的情况

这时如果再执行Pop操作,要先将s1栈中的元素全部弹入到s2栈中,再执行Pop操作,

具体如图3所示:


图3 将s1栈中的元素全部弹入到s2栈中

如果执行的是Push操作,只需将入队元素压入到s1栈即可,

如图4所示:

图4 执行Push操作,将入队元素直接压入到s1栈中

这样就巧妙地利用s1栈和s2栈高效地实现了一个队列。

AC代码如下:

#include
#include
#include
using namespace std;
 
/**
* 队列的入队元素直接压入s1栈,队列出队元素直接从s2栈弹出
* s1栈从栈底到栈顶依次保存队列的后半段,s2栈从栈顶到栈底依次保存队列的前半段
* 在执行出队操作时,只有当s2栈为空时,才将s1栈中的元素全部倒入s2栈中
* 这样就不会出现"倒来倒去"的现象
* @param n  代表队列操作的个数
* @return void
*/
void twoStackToOneQueue(int n)
{
 stack  s1;                   // s1的栈顶元素保存着队列的队尾元素
 stack  s2;                   // s2的栈顶元素保存着队列的队首元素
 int i = 0;
 int x;
 char operation[20];               // 记录操作
 while(i < n)
 {
     scanf("%s",operation);
     if(0 == strcmp(operation,"PUSH"))   // 将元素压入队尾 PUSH x
     {
        scanf("%d",&x);
        s1.push(x);                      // 执行入队操作
     }
     else                                // 将队首元素弹出 POP
     {
        if(true == s2.empty())           // 如果s2为空,则将s1中的元素全部弹入到s2中,否则直接跳过次语句块
        {
          while(true != s1.empty())
          {
              s2.push(s1.top());
              s1.pop();
          }
        }
 
        if(true != s2.empty())          // 如果s2不为空 则输出并弹出s2的栈顶元素
        {
            printf("%d\n",s2.top());
            s2.pop();
        }
 
        else                           // 如果s2为空,则输出-1
        {
            printf("-1\n");
        }
     }
     i++;
 }
}
 
int main()
{
    int n;
    scanf("%d",&n);
    twoStackToOneQueue(n);
    return 0;
}
 
/**************************************************************
    Problem: 1512
    User: blueshell
    Language: C++
    Result: Accepted
    Time:70 ms
    Memory:1184 kb
****************************************************************/


你可能感兴趣的:(九度OJ-剑指Offer)