题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
前言
现在我越来越觉得变成的时候思想很重要,不是编完了就完事了,而应该清楚自己是怎么想的,有没有更好的想法,自己的思维漏洞在哪里。看别人写的代码的时候,更应该思考别人的思想是什么,或者简单一点,思路是什么,下次碰到一个类似的题目应该怎么去想。如果不去思考这些东西,那么进步是微小的,好一点的结果也只是你记住了这道题的解法,是无法融会贯通的。而如果你懂了编程背后的思想,就可以举一反三,触类旁通。这样收获才是巨大的。当然了,冰冻三尺,非一日之功。我会慢慢来,总有一天,我会变成编程高手。
分析
判断弹出序列是否对应压栈序列,就要看其有没有违反栈的定义:后进先出。那么就要找到一个元素 a 在另一个元素 b 之前进栈,却在其之后进栈。直觉是根据它们在两个数组中的下标来判断,不过发现这样行不通,需要加入一个第三者元素 c 来辅助判断。于是就开始了尝试的过程,然后我找到了方法:假设有三个元素进栈的顺序为x, y, z, 且满足 x < y < z, 但出栈的顺序却为 z,x, y, 按照数组下标排序的话,进栈为:小,中,大,出栈为:大,小,中,那么,就说明出错了。
这个做法需要找到这个规律,但有些人不一定能找到,且时间复杂度为 O(n)2O(n)^2O(n)2, 偏高。后来我看了别人的做法,知道了 模拟 这种方法,即一件事的发生是有过程的,那么就编程取模拟这个过程,就能发现结果是对是错。发现了这个方法后,我不急于去看别人的代码,想自己先实现一边,再和别人的代码对照。
模拟进栈与出栈:我的思路是遍历 popV 中的每一个元素,判断其是否已压入栈中,若没有,那么对 pushV 进行压入,一直到 pushV[i]=popV[j]pushV[i] = popV[j]pushV[i]=popV[j] 为止,然后去除栈顶元素;若已在栈中,那么判断栈顶元素是否等于 popV[j], 正确的答案是应该相等的。若出错,结束,否则重复上述过程。后来,与别人的代码进行比较,发现我的代码写得真是太烂了。
- 为了判断 popV[j]popV[j]popV[j] 是否在栈中,我用了 map 数组,即若元素进栈,则将其值置 1,实际上这是没必要的,只需判断在栈顶就可以了,因为 popV[j]popV[j]popV[j] 是当前要出栈的元素。
- 我将pushV[i]pushV[i]pushV[i] 和 popV[j]popV[j]popV[j] 作比较,这样走了弯路,因为有栈了,popV[j]popV[j]popV[j] 应该直接与栈顶元素作比较,有多个可比较元素的时候,与谁比较是不一样的。
这个题目之后有必要再做一遍,应该尽量做到用最简洁的方式 来做。
下面就贴一下我的不尽如人意的代码吧。
//方法一
bool IsPopOrder(vector<int> pushV, vector<int> popV) {
if (pushV.empty() || popV.empty()) {
return 0;
}
map<int, int> Map;
for (int i = 0; i < pushV.size(); ++i) {
Map[pushV[i]] = i;
}
if (pushV.size() == 1 && pushV[0] != popV[0]) {
return 0;
}
for (int i = 1; i < popV.size() - 1; ++i) {
for (int j = 0; j < i; ++j) {
if (!Map.count(popV[j]) || !Map.count(popV[i]))
return 0;
if (Map[popV[j]] > Map[popV[i]]) {
for (int k = i + 1; k < popV.size(); ++k) {
if (!Map.count(popV[k])) {
return 0;
}
if (Map[popV[k]] > Map[popV[i]] && Map[popV[k]] < Map[popV[j]]) {
return 0;
}
}
}
}
}
return 1;
}
//方法二
bool IsPopOrder2(vector<int> pushV, vector<int> popV) {
vector<int> s;
int n = pushV.size();
map<int, int> in;
int i = 0;
int j = 0;
if (pushV.size() == 1 && pushV[0] != popV[0]) {
return 0;
}
for (i = 0; i < n; ++i) {
if (in.count(popV[i])) {
if (!s.empty() && s[s.size() - 1] == popV[i]) {
s.pop_back();
}
else {
return 0;
}
}
else { // 栈中没有该元素,那么一直进栈
for (; j < n; ++j) {
if (pushV[j] != popV[i]) {
s.push_back(pushV[j]);
in[pushV[j]] = 1; //代表该元素已进栈
}
else {
s.push_back(pushV[j]);
in[pushV[j]] = 1;
++j;
break;
}
}
//没有该元素 popV[i]
/*if (j == n) {
return 0;
}*/
s.pop_back();
}
}
if (i == n) {
return 1;
}
return 0;
}