4.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。 假设压入栈的所有数字均不想等。
例如: 序列 1 2 3 4 5 是某栈的压栈序列, 序列 4 5 3 2 1是该压栈序列对应的一个弹出序列, 但 4 3 5 1 2就不可能是该压栈序列的弹出序列。
思路: 首先我们来 理解下题意, 有些人可能会这么想, 1 2 3 4 5为压栈序列, 弹出序列一定是 5 4 3 2 1 啊
4 5 3 2 1 一定不是它的一个弹出序列。 并不是这样的 , 我们来分析 , 如果我们 压入 123 Pop 一次 再压入 4 5
此时全部Pop 则, 压入序列为 1 2 3 4 5 弹出序列为 3 5 4 2 1
理清了题意, 我们此时进行分析. 先给一串 简单 入栈出栈序列
入栈: 1 2 3 4 5
出栈: 3 5 4 2 1
我们首先来看弹出序列, 弹出序列的第一个元素为3, 则弹出3时,3必须在栈顶。 入栈 -->1 -->2 -->3, 直到要弹出元素与栈顶元素相等(此时为3), 弹出。
接下来要弹出元素为 5, 和栈顶元素(2)不相等, 即继续入栈, 直到遇到元素 5. 入栈 -->4 -->5. 弹出5。 接下来, 栈顶元素为4 , 要弹出元素为4, 弹出。
重复上述过程, 最后,如果入栈序列已经为空, 但 栈顶 依旧和 弹出序列元素 不相等, 则他们不匹配。 如果 两者都 为空, 则它们匹配。
题目条件: 所有数字均不相等。 ---> 保证了以上想法的正确性。
为了更好的验证我们的想法, 判断这个问题, 我们使用一个辅助栈。
例如: 序列 1 2 3 4 5 是某栈的压栈序列, 序列 4 5 3 2 1是该压栈序列对应的一个弹出序列, 但 4 3 5 1 2就不可能是该压栈序列的弹出序列。
思路: 首先我们来 理解下题意, 有些人可能会这么想, 1 2 3 4 5为压栈序列, 弹出序列一定是 5 4 3 2 1 啊
4 5 3 2 1 一定不是它的一个弹出序列。 并不是这样的 , 我们来分析 , 如果我们 压入 123 Pop 一次 再压入 4 5
此时全部Pop 则, 压入序列为 1 2 3 4 5 弹出序列为 3 5 4 2 1
理清了题意, 我们此时进行分析. 先给一串 简单 入栈出栈序列
入栈: 1 2 3 4 5
出栈: 3 5 4 2 1
我们首先来看弹出序列, 弹出序列的第一个元素为3, 则弹出3时,3必须在栈顶。 入栈 -->1 -->2 -->3, 直到要弹出元素与栈顶元素相等(此时为3), 弹出。
接下来要弹出元素为 5, 和栈顶元素(2)不相等, 即继续入栈, 直到遇到元素 5. 入栈 -->4 -->5. 弹出5。 接下来, 栈顶元素为4 , 要弹出元素为4, 弹出。
重复上述过程, 最后,如果入栈序列已经为空, 但 栈顶 依旧和 弹出序列元素 不相等, 则他们不匹配。 如果 两者都 为空, 则它们匹配。
题目条件: 所有数字均不相等。 ---> 保证了以上想法的正确性。
为了更好的验证我们的想法, 判断这个问题, 我们使用一个辅助栈。
我们使用 两种方法 来 实现 并进行测试
:
#include <stack>
#include <iostream>
#include <windows.h>
using namespace std;
//我们就不考虑那种, 入栈序列 和 出栈序列 元素个数不相等的问题了, 假设他们相等, 长度皆为length.
//因为它们的长度相同, 我们仅通过 length 来判断 入栈序列是否已经结束(防止数组越界)。 出栈序列我们不关心它走到尽头,
//因为我们的代码实现中, 保证了出栈序列数组不会越界。
bool IsPopOrder1( const int* pPush, const int* pPop, int length )
{
stack<int> s;
while ( 0 != length || 0 != s.size( ) )
{
//分两种情况:
//第一种 入栈序列还有元素
if ( 0 != length )
{
if ( 0 != s.size( ) )
{
if ( *pPop == s.top( ) ) //注意, 可以 s.push( *push++ ) 因为 push后, pPush是一定要++的。 但 *pPop++ == s.top( ) 就是错的了。 因为 只有相等才会 执行 s.pop( ) 接着才会 ++pPop. 而不是每次验证后都++ ---> *pPop++(即加加的是指针,而不是值)
{
s.pop( );
++pPop;
}
else
{
while ( 0 != length && *pPop != s.top( ) )
{
s.push( *pPush++ );
--length;
}
if ( 0 == length && *pPop != s.top( ) )
return false;
s.pop( );
++pPop;
}
}
else
{
//这样写是错的, 栈为空 ,怎么用 *pPop != s.top( )这个条件, 所以 do while 循环
//while ( 0 != length && *pPop != s.top( ) )
//{
// s.push( *pPush++ );
//
// --length;
//}
do {
s.push( *pPush++ );
--length;
} while ( 0 != length && *pPop != s.top( ) );
if ( 0 == length && *pPop != s.top( ) )
return false;
//运行到这里, 则,不管是 length 等不等于0。 *pPop == s.top( ) 这个条件一定是成立的!
s.pop( );
pPop++;
}
}
else
{
//第二种: 入栈序列已经 没有元素 了
if ( *pPop == s.top( ) )
{
s.pop( );
++pPop;
}
else
return false;
}
}
return true;
}
bool IsPopOrder2( const int* pPush, const int* pPop, int nLength )//如果 不用 bPossible 这个变量, 则代码如下所示, 程序会少执行几步代码, 不过 "或许 牺牲" 了 代码的 可读性, 与 简明性.
{
//bool bPossible = false;
if ( NULL != pPush && NULL != pPop && nLength > 0 )
{
const int* pNextPush = pPush;
const int* pNextPop = pPop;
stack<int> stackData;
while ( pNextPop - pPop < nLength )
{
while ( stackData.empty( ) || *pNextPop != stackData.top( ) )
{
if ( pNextPush - pPush == nLength )
//break;
return false;
stackData.push( *pNextPush );
++pNextPush;
}
//if ( *pNextPop != stackData.top( ) )
// break;
stackData.pop( );
++pNextPop;
}
//if ( stackData.empty( ) && nLength == pNextPop - pPop )
// bPossible = true;
return true;
}
//return bPossible;
}
void Test( )
{
int push[] = { 1, 2, 3, 4, 5 };
int pop1[] = { 3, 5, 4, 2, 1 }; //true
int pop2[] = { 3, 5, 4, 1, 2 }; //false
int length = sizeof( push ) / sizeof( push[0] );
cout << "1 :\n";
cout << IsPopOrder1( push, pop1, length ) << endl;
cout << IsPopOrder1( push, pop2, length ) << endl << endl;
cout << "2 :\n";
cout << IsPopOrder2( push, pop1, length ) << endl;
cout << IsPopOrder2( push, pop2, length ) << endl;
}
int main( )
{
Test( );
system( "pause" );
return 0;
}