剑指 31 栈的压入、弹出序列 【贪心算法】
原题目
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof
示例 1:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:
输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。
考查知识点
贪心
贪心算法现在还不是很了解,看了力扣题解才知道这里用到了贪心
自己的第一遍解法
在纸上写写画画,发现下一个弹出的元素
只有两种情况 {当前栈顶元素
,pushed中的下一个数字
}。基于这样的思路歇了如下代码:
class Solution_failed {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
if (pushed.empty() || popped.empty())
return false;
vector<int> s;
//1)将pushed数组元素逐个加入栈中,直到遇到poped第一个元素
while (popped[0] != pushed[0] && !pushed.empty())
{
s.push_back(pushed[0]);
pushed.erase(pushed.begin());
continue;
}
s.push_back(pushed[0]);
pushed.erase(pushed.begin());
if (s.empty())
return false;
while (!popped.empty())
{
//2) pushed.back() == popped[popIndex]
// 检查poped[新的popIndex]与s.back()是否一样
s.pop_back();
popped.erase(popped.begin());
if (popped[0] != s.back() && !pushed.empty()) {
s.push_back(pushed[0]);
pushed.erase(pushed.begin());
if (popped[0] != s.back())
return false;
}
if (popped[0] != s.back() && pushed.empty())
return false;
}
return true;
}
};
但是这样的思路被示例给局限住了,下一个弹出的元素
应该是这两种情况 {当前栈顶元素
,pushed中接下来的某个数字
}
好的解法
参考:力扣题解图解 模拟入栈操作,贪心算法
这里就是模拟了入栈和出栈(一边入栈还要考虑是否出栈)的实际操作。pushed
中新元素的每次入栈,都要判断栈顶元素是否就是poped[j]
,如果满足该条件,说明可以弹出栈顶元素,并且弹出栈顶元素后还要循环判断最新的栈顶元素是否与下一个poped[j]
相同,满足条件就接着弹出栈顶元素。
class Solution
{
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped)
{
stack<int> s;
int n = popped.size();
int j = 0; //指向poped数组当前元素的下标
for (int& i : pushed)
{
s.push(i);
while (!s.empty() && j<n && s.top()==popped[j])
{
s.pop();
++j;
}
}
return s.empty();
}
};