目录
刷题日期:21:3224 星期三 2021年4月7日
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 31. 栈的压入、弹出序列
难度中等161
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
示例 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 之前弹出。
提示:
0 <= pushed.length == popped.length <= 10000 <= pushed[i], popped[i] < 1000pushed是popped的排列。
题目分析
并不是简单的倒序,首先判断是否完全是倒序,如果不是的话从第一个输出开始是否与原栈匹配,后面是否为倒序,如果有误则错误。
如果下一个是栈顶,直接弹出
如果不是,则把剩下的压入辅助栈,直到栈顶是,都压入还不满足,则错误。
初始解答:
对Java栈的操作还比较生,参考了【剑指Offer】个人学习笔记_09_ 用两个栈实现队列的操作方法。
class Solution {
Stack<Integer> stack1; //两个辅助栈
Stack<Integer> stack2;
public boolean validateStackSequences(int[] pushed, int[] popped) {
boolean bP = false; //判断flag
stack1 = new Stack<>(); //栈的定义方法,学习了
stack2 = new Stack<>(); //感觉其实是链表
stack1.add(pushed[0]); //初始化
int i = 0;
for (int j = 0; j < popped.length; j++) {
while(stack1.pop() != popped[0]) { //如果不是则一直压
stack1.add(pushed[i++]);
if (i > pushed.length) return false;
}
//如果上面跑完而且没返回错误则说明找到了项
}
//一直找popped元素
return true;
}
}
写不出来,还是参考别人的吧。
参考了方法一:
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Deque<Integer> stack =new ArrayDeque(); //定义辅助栈
int j = 0;
for (int elem:pushed) { //pushed里面的每一个元素遍历
stack.push(elem); //挨个压入
while (j < popped.length && !stack.isEmpty() && stack.peek() == popped[j]) {
// 当所判断的元素还属于popped,辅助栈非空,并且栈顶元素为popped目前第一个元素
stack.pop();
j++;
}
//循环一次代表找到一个
}
return j == popped.length; //相等则意味着全找到了
}
}
用了辅助栈,j自增和两层循环,效率较低
执行结果:通过
显示详情
执行用时:3 ms, 在所有 Java 提交中击败了33.87%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了16.66%的用户
往K神的代码靠:
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Deque<Integer> stack =new ArrayDeque(); //定义辅助栈
int j = 0;
for (int elem:pushed) { //pushed里面的每一个元素遍历
stack.push(elem); //挨个压入
while (!stack.isEmpty() && stack.peek() == popped[j]) {
//省掉了第一个判断
//辅助栈非空,并且栈顶元素为popped目前第一个元素
//学习.peek方法,而不是还得pop。
stack.pop();
j++;
}
//循环一次代表找到一个
}
return stack.isEmpty(); //跑完循环而且全部出栈,说明正确
}
}
少了一项判断,时间效率上来了。执行结果:通过
显示详情
执行用时:2 ms, 在所有 Java 提交中击败了95.74%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了15.46%的用户
这里的解答与方法四中的第二种解法一样,学习空间效率也更高的解法,不用辅助栈
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
int i = 0, j = 0;
for (int elem:pushed) { //pushed里面的每一个元素遍历
pushed[i] = (elem); //这一步注释则解答错误
while (i >= 0 && pushed[i] == popped[j]) {
//循环成立则说明在pushed中找到了popped中的第一二三个
j++;
i--;
//每找到一个则popped往后,pushed往前
}
//没有匹配到则在pushed后面继续找
i++;
//循环一次代表找到一个
}
return i == 0; //i=0则说明找完了,不等于0则说明没匹配到卡一半了
}
}
只能说太骚太强了,每一句都是必须的,思路缜密,想学习只能靠记了,看一遍感觉都理解不太了。
执行结果:通过
显示详情
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了64.44%的用户
学习他人:
方法一:
宝石L1 (编辑过)2020-02-28
Java题解 简单明了
判断合不合法,用个栈试一试: 把压栈的元素按顺序压入,当栈顶元素和出栈的第一个元素相同,则将该元素弹出,出栈列表指针后移并继续判断。最后判断出栈列表指针是否指向出栈列表的末尾即可。
public boolean validateStackSequences(int[] pushed, int[] popped) {
Deque<Integer> stack = new ArrayDeque();
int j = 0;
for (int elem : pushed) {
stack.push(elem);
while (j < popped.length && !stack.isEmpty() && stack.peek() == popped[j]) {
stack.pop();
j++;
}
}
return j == popped.length;
}
方法二:
梵_L1 2021-03-14
使用数组代替栈结构,优化了一定空间
public boolean validateStackSequences(int[] pushed, int[] popped) {
int len = pushed.length;
int indexPush =0,indexPop=0;
int[] mockStack =new int[len];
int index=0;
while(indexPush<len&&indexPop<len){
//入栈
mockStack[index]=pushed[indexPush++];
//出栈
while(indexPop<len&&index>=0&&popped[indexPop]==mockStack[index]){
index--;
indexPop++;
}
index++;
}
return index==0;
}
方法三:
K神 考虑借用一个辅助栈 stackstack ,模拟 压入 / 弹出操作的排列。根据是否模拟成功,即可得到结果。
入栈操作: 按照压栈序列的顺序执行。
出栈操作: 每次入栈后,循环判断 “栈顶元素 == 弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。
作者:jyd
链接:https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/solution/mian-shi-ti-31-zhan-de-ya-ru-dan-chu-xu-lie-mo-n-2/
来源:力扣(LeetCode)
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Stack<Integer> stack = new Stack<>();
int i = 0;
for(int num : pushed) {
stack.push(num); // num 入栈
while(!stack.isEmpty() && stack.peek() == popped[i]) { // 循环判断与出栈
stack.pop();
i++;
}
}
return stack.isEmpty();
}
}
方法四
一个肥宅L1 2020-07-23
O(1) 空间 O(n) 时间 太强了。
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
int i = 0, j = 0;
for (int e : pushed) {
pushed[i] = e;
while (i >= 0 && pushed[i] == popped[j]) {
j++;
i--;
}
i++;
}
return i == 0;
}
}
O(n) 时间 & 空间
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
int index = 0;
Deque<Integer> stack = new ArrayDeque<>();
for (int e : pushed) {
stack.push(e);
while (!stack.isEmpty() && stack.peek() == popped[index]) {
stack.pop();
index++;
}
}
return index == popped.length;
}
}
总结
以上就是本题的内容和学习过程了,不用辅助栈的思路很是巧妙,理解正常的解法目前来说就足够了。
欢迎讨论,共同进步。
本文介绍了如何使用Java解决LeetCode题目31,利用栈的压入和弹出操作判断序列是否合法,通过对比和优化不同解法,重点讲解了不使用辅助栈的高效解决方案。
404

被折叠的 条评论
为什么被折叠?



