1.问题描述
【问题描述】给出一个堆栈的输入序列,试判断一个序列是否能够由这个堆栈输出。如果能,则为有效输出,返回总的出栈次数,如果不能,则为无效输出,返回0。序列的输入及输出都是从左往右。
1、输入输出序列皆为正整数,可能有重复的数字
2、如果一个数字在输入序列中没有出现,但在输出序列中出现,则为无效输出。
3、如果一个数字在输入序列中出现,但在输出序列中没有出现,只要输出可以通过对输入数字进行出栈操作获取,仍然为有效输出。(重要伏笔)
【输入形式】第一行包含两个数字:输入序列的长度与输出序列的长度;第二行为输入序列的数字;第三行为输出序列的数字。输入数据以空格隔开。
【输出形式】如果是一个有效的出栈序列,则返回总的出栈次数, 否则返回0
【样例输入1】
5 5
1 2 3 4 5
4 5 3 2 1
【样例输出】5
【样例说明】
可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4, push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
通过5次pop操作可以得到输出序列,因此返回5
【样例输入2】
5 5
1 2 3 4 5
4 3 5 1 2
【样例输出】0
【样例说明】
1不能在2之前输出,因此返回0
【评分标准】10个测试用例,每个10分
2.解决思路
首先我尝试的思路是抽象出可输出序列的规律。
思路一
分析问题
首先来考察以下不能输出的序列示例:
输入:1 2 3 4 5
输出:1 2 5 3 4
为什么这个示例不能输出呢?显然重点在于数字5的位置。
5在输入序列的第五位,却在输出序列的第三位。这也就意味着,在输出5之后,输入在5之前且还未输出的数都在栈内,这一特征反映在输出序列中,就是
————————————
对于输出序列中的数字x而言:
对于所有满足:
1.输入位置在x之前
2.输出位置在x之后
的数字——
这样的数字在x输出之前一定已经在栈内了,所以必须服从栈的输出规律“后进先出”,也就是
——必须按照输入顺序的反序输出
————————————
在以上示例中,数字3和4的输入位置在5之前,而输出位置在5之后,所以它们应该按照输入顺序的反序输出,也就是“5 4 3”,但是示例中是“5 3 4”,所以该示例不能输出。
构思算法
创建变量:
变量名 | 类型 | 描述 |
---|---|---|
inLen/outLen | int | 输入/输出序列长度 |
st/outst | *int | 动态数组存放输入顺序/输出顺序 |
curOrd | int | 现在验证的数据在输入序列中的顺序(下文不注明则顺序都指输入顺序) |
preOrd | int | 上一个验证的数据的顺序 |
Ord | int | 已验证的数字中的最大顺序 |
flag | bool | 记录是否已经逆序(称两数输出次序和输入次序相反为逆序)输出一次 |
—————————————————————————————————
算法:
【虽然根据以上思路,看上去对于输出序列中的每一个数字,都要对它输出序列中更前的数字进行验证,但是实际上,由于条件1描述的是x之前所有的数字,且输出位置在x更靠后的数字之后,自然也在x之后,所以满足了输入序列中更靠后的数字的要求,就已经满足了前面所有数字的要求】
1.将目前验证过的数字中顺序最靠后的数字的顺序存放在Ord中,上一个验证过的数字的顺序存放在preOrd中。
2.读入输出序列的下一个数字(记为y),并找出y在输入序列上的顺序,存放在变量curOrd(current order)中;
验证curOrd是否满足:
1.curOrd>preOrd
2.flag==false(表示上次输出是反序输出)
3.curOrd<Ord
全满足则返回0。
————————————————————————————————
代码如下:
#include<iostream>
using namespace std;
int main()
{
int inLen(0),outLen(0),preOrd(-1),Ord(-1),curOrd(0),cur(1),*st=NULL,*outst=NULL;//注意cur的开始值
bool flag(true);
//输入部分
cin>>inLen