【剑指offer】面试题22:栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、5是某栈的压栈序列,但4、3、5、1、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 }
注意循环退出的条件。
本文完。