【前端js】实现剑指offer|leetcode(三)——栈和队列题目集合
一、栈
1. 用两个栈实现队列(牛客网-剑指offer)
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
测试用例
-
空队列
入队出队 -
非空队列
入队出队 - 连续出队直到
队列为空
思路
- 栈只能从栈顶出入,队列从队首出,队尾入,借助两个栈:
栈1的顶为队尾
,栈2的顶为队首
-
push
从队尾压入一个元素,从s1
压入,栈空和非空情况一样,无返回值 -
pop
从队首一个弹出元素,s2
不空时队首在s2栈顶
,s2
空时队首在s1栈底
,需要先把s1中所有元素依次弹入s2,然后弹出s2栈顶
-
注意从A中弹出所有元素压入B时,因为A数组改变,所以需要先把
数组长度
存下来,再使用保存的值控制for循环
- 如果
s1空
,队列为空,pop
弹出null
- 代码
var stack1 = [],
// var stack1 = [],
stack2 = []; //定义两个栈
//入队,修改原数组,无返回值
function push(node) {
// write code here
stack1.push(node); //压入栈1
}
//出队,修改原数组,返回出队元素
function pop() {
// write code here
//栈2不空,返回栈2栈顶元素
if (stack2.length !== 0) return stack2.pop();
//栈2空,返回栈1栈底元素
if (stack2.length === 0) {
//栈1空,返回空
if (stack1.length === 0) return null;
//栈1不空,将栈1元素全部放入栈2,然后返回栈顶元素
let len =stack1.length;//for循环修改了stack1数组,所以要先保存len作为循环的计数器
for (let i = 0; i < len; i++) {
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
2. 包含min函数的栈(牛客网-剑指offer)
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,时间复杂度应为O(1)
。
测试用例
-
push
——入栈元素是第一个,入栈元素是当前最小值,入栈元素不是当前最小值, -
pop
——出栈元素不是当前最小值,入栈元素是当前最小值 -
pop
——连续出栈直到栈为空
-
min
——栈为空,栈不为空
思路
- 时间复杂度应为
O(1)
所以应该保存每次栈压入元素之后的最小值,新建一个stkMin
,和stk
同步 -
push
——栈元素是第一个,入栈元素是当前最小值时,stkMin
压入node,否则压入stkMin
栈顶元素(之前的最小值依然是最小值) -
pop
——stkMin
和stk
同步出栈 -
min
——返回stkMin
栈顶元素
代码
var stk = [];
var stkMin = [];
function push(node) {
// write code here
stk.push(node);
stkMin.length === 0 || node < stkMin[stkMin.length - 1]
? stkMin.push(node) //stkMin空/node小于栈顶元素时,node为最小值
: stkMin.push(stkMin[stkMin.length - 1]); //node大于栈顶元素时,栈顶元素为最小值
}
function pop() {
// write code here
if (stk.length === 0) return null;
stkMin.pop();
return stk.pop();
}
function top() {
// write code here
return stk[stk.length - 1]; //返回栈顶元素
}
function min() {
// write code here
return stkMin[stkMin.length - 1];
}
3. 栈的压入、弹出序列(牛客网-剑指offer)
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。
测试用例
-
特殊情况1
——两个数组中一个/两个为空,或者长度不相等 -
特殊情况2
——两个数组只有一个元素 -
正确
——是弹出序列 -
错误
——不是弹出序列
思路
- 判断一个序列是不是栈的弹出序列,其实是判断将序列1压入栈时,
栈顶元素
是否可以形成序列2,栈顶元素
有三种可能: - 1.当前栈顶
- 2.弹出栈顶之后的新栈顶
- 3.继续压入新的栈顶
- 比较顺序:1,2,3,可以最多的弹出所有元素
- 借助一个
辅助栈
,依次把所有元素压入这个栈里,设置一个指针idx
指向需要弹出的元素,初始指向弹出序列的第一个元素 - 每次压入之后,都比较
idx
元素和栈顶元素是否相等,如果相等,就弹出这个值,idx
指向下一个,循环比较
所有相等值全部弹出,直到两个值不等,不再弹出序列,继续压入
- 数组里所有元素都压栈完成以后,如果
辅助栈
还有没弹出的元素,就代表不是弹出序列
,如果栈空
了,就代表是弹出序列
。
代码
function IsPopOrder(pushV, popV) {
// write code here
//任意空数组/数组长度不相等,不满足条件
if (pushV.length === 0 || popV.length === 0 || popV.length !== pushV.length)
return false;
//单个数组,比较一个元素
if (pushV.length === 1 && popV.length === 1) return pushV[0] === popV[0];
let stk = []; //辅助栈
let idx = 0; //指针,指向popV的第一个元素
//将pushV压入辅助栈
for (let i = 0; i < pushV.length; i++) {
stk.push(pushV[i]);
// stk空或者栈顶元素和popV指针的元素不相等,跳过循环,继续入栈
// 栈顶元素和popV指针的元素相等时,循环比较栈顶元素和pop中指针指向的元素
while (stk.length != 0 && stk[stk.length - 1] === popV[idx]) {
stk.pop(); // 栈顶元素出栈
idx++; //指针下移,继续比较
}
}
return stk.length === 0; //所有popV中的元素都按顺序出栈,则是一个弹出序列
}
IsPopOrder([1, 2, 3, 4, 5], [4, 5, 3, 2, 1]);
IsPopOrder([1], [2]);