• 【剑指offer】面试题22:栈的压入、弹出序列


    题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、234、5是某栈的压栈序列,但4、351、2就不可能是该压栈序列的弹出序列。(假设各个元素不等)

     解决这个问题很直观的想法就是建立一个辅助栈,把输入的第一个序列push序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数字。

    pushOrder:1、2、3、4、5;

    一:popOrder:4、5、3、2、1。

    1、第一个希望弹出的数字是 4,因此 4 需要先压入到辅助栈里面。由于压入栈的顺序已经由压栈序列push序列确定了,所以在把 4 压入之前,数字 1,2,3 都需要先压入到辅助栈里面。此时辅助栈里包含 4 个数字。分别为 4,3,2,1。其中 4 为栈顶元素。压入1、2、3、4之后,把 4 弹出。

    2、现在希望被弹出的数字为 5,由于它不是栈顶元素,因此我们接着在第一个序列push序列中把 4 以后的数字压入到辅助栈里面,直到压入了数字 5。把 5 压入栈之后,5 为栈顶元素,就可以弹出 5 了。

    3、接下来希望被弹出的数字为3, 现在栈顶元素为 3,则元素 3 可以直接被弹出。接下来依次为 2 和 1.

    4、弹出 1 之后,栈为空,popOrder序列已经遍历完,所以此 popOrder 序列可以是 pushOrder 弹出序列之一。

    具体操作过程如下图:

    二:popOrder:4、3、5、1、2。

    1、第一个弹出的数字 4 的情况和一相同;

    2、在 4 弹出之后,3 位于栈顶,可以直接弹出。此时栈顶元素为 2;

    3、接下来希望弹出的数字是 5, 由于 5 不是现在的栈顶元素,因此到pushOrder序列中把没有进栈的数字压入辅助栈中,直到遇到数字 5,把数字 5 压入栈之后,5 就位于栈顶了,可以弹出数字 5。此时栈中包含两个数字 1 和 2,其中 2 位于栈顶。

    4、接下来希望弹出的数字为 1, 不在栈顶位置,我们需要从压栈pushOrder序列中尚未压入栈的数字中去查找数字 1。但是此时压栈序列中所有数字都已经压入栈了。所以该序列不是序列 1、2、3、4、5 对应的弹出序列之一。

    具体过程如下图:

    综上所述,我们可以找到一个规律:

    1、如果下一个弹出的数字恰好是栈顶数字,那么直接弹出;

    2、如果下一个弹出的数字不在栈顶位置,那么我们把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止;

    3、如果所有的数字都压入栈了,但还没有找到下一个弹出的数字,那么该数字不可能是一个弹出序列。

    下面为测试代码:

     1 // IsPopOrder.cpp
     2 #include <iostream>
     3 #include <stack>
     4 
     5 using namespace std;
     6 
     7 bool IsPopOrder(const int* pPushOrder, const int* pPopOrder, int nLen)
     8 {
     9    bool bPossible = false;
    10 
    11    if(!pPushOrder || !pPopOrder || nLen > 0)
    12    {
    13       const int* pNextPush = pPushOrder;
    14       const int* pNextPop = pPopOrder;
    15 
    16       std::stack<int> stackData;
    17 
    18       // 当 pPopOrder 序列遍历完之后退出循环
    19       while(pNextPop - pPopOrder < nLen)
    20       {
    21          // 如果栈stackData为空或者栈顶元素与*pNextPop不等,进栈
    22          while(stackData.empty() || stackData.top() != *pNextPop)
    23          {
    24             if(pNextPush - pPushOrder == nLen)
    25                break;
    26 
    27             stackData.push(*pNextPush);
    28             ++pNextPush;
    29          }
    30          // 栈非空,栈顶元素不等于*pNextPop,但是pNextPush已经遍历结束
    31          if(stackData.top() != *pNextPop)
    32             break;
    33 
    34          stackData.pop();
    35          ++pNextPop;
    36       }
    37 
    38       if(stackData.empty() && pNextPop - pPopOrder == nLen)
    39          bPossible = true;
    40    }
    41 
    42    return bPossible;
    43 }
    44 
    45 int main(int argc, char const *argv[])
    46 {
    47    const int N = 5;
    48    int pushOrder[N] = {1, 2, 3, 4, 5};
    49 
    50    int popOrder1[N] = {4, 5, 3, 2, 1};
    51    bool isTrue = IsPopOrder(pushOrder, popOrder1, N);
    52    cout << "Test1: " << isTrue << endl;
    53 
    54    int popOrder2[N] = {4, 3, 5, 1, 2};
    55    bool isTrue2 = IsPopOrder(pushOrder, popOrder2, N);
    56    cout << "Test2: " << isTrue2 << endl;
    57 
    58    return 0;
    59 }
    View Code
    注意循环退出的条件。

    本文完。

  • 相关阅读:
    团队开发冲刺第二十天
    团队开发冲刺第十九天
    第十六周进度总结
    学期课后个人总结
    用户场景分析
    第十五周进度总结
    对正在使用的输入法进行评价
    java中实现客户姓名添加和显示
    指定查找区间,查找学生姓名并显示是否修改成功
    linux下如何修改文件的权限chmod
  • 原文地址:https://www.cnblogs.com/xfxu/p/4616680.html
Copyright © 2020-2023  润新知