剑指Offer JavaScript-栈和队列专题
剑指Offer JavaScript-栈和队列专题
用两个栈实现队列
1. 题目描述
用两个栈实现一个队列。队列的声明如下:
请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。
2. 解题思路
一个栈用来存储插入队列数据,一个栈用来从队列中取出数据。
从第一个栈向第二个栈转移数据的过程中:数据的性质已经从后入先出变成了先入先出。
3. 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Queue {
constructor() {
this.stack1 = [];
this.stack2 = [];
}
appendTail(value) {
// 新插入队列的数据都放在 stack1
this.stack1.splice(0, 0, value);
}
deleteHead() {
// 将要取出的值都从stack2中取
// 如果stack2为空,那么将 stack1 中的元素都转移过来
// 此时,stack2中的元素顺序已经被改变了,满足队列的条件
if (this.stack2.length === 0) {
let length = this.stack1.length;
for (let i = 0; i < length; ++i) {
this.stack2.splice(0, 0, this.stack1.shift());
}
}
return this.stack2.length === 0 ? null : this.stack2.shift();
}
}
/**
* 测试代码
*/
let queue = new Queue();
queue.appendTail(1);
queue.appendTail(2);
queue.appendTail(3);
console.log(queue.deleteHead());
queue.appendTail(1);
console.log(queue.deleteHead());
console.log(queue.deleteHead());
console.log(queue.deleteHead());
包含min函数的栈
1. 题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数。在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
2. 思路分析
有关栈的题目,可以考虑使用“辅助栈”,即利用空间换时间的方法。
这道题就是借助“辅助栈”来实现。当有新元素被 push 进普通栈的时候,程序比较新元素和辅助栈中的原有元素,选出最小的元素,将其放入辅助栈。
根据栈的特点和操作思路,辅助栈顶的元素就是最小元素。并且辅助栈的元素和普通栈的元素是“一一对应”的。
3. 代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* 包含Min函数的栈
*/
class MinStack {
constructor() {
this.stack = []; // 数据栈
this.minStack = []; // 辅助栈
}
push(item) {
const minLength = this.minStack.length;
this.stack.push(item);
if (minLength === 0) {
// 初始情况: 直接放入
this.minStack.push(item);
} else {
if (item < this.minStack[minLength - 1]) {
// 新元素 < 辅助栈的最小元素: 将新元素放入
this.minStack.push(item);
} else {
// 否则,为了保持2个栈的对应关系,放入辅助栈最小元素
this.minStack.push(this.minStack[minLength - 1]);
}
}
}
pop() {
if (this.stack.length === 0) {
return null;
}
this.stack.pop();
return this.minStack.pop();
}
min() {
const minLength = this.minStack.length;
if (minLength === 0) {
return null;
}
return this.minStack[minLength - 1];
}
}
/**
* 以下是测试代码
*/
const minStack = new MinStack();
minStack.push(3);
minStack.push(4);
minStack.push(2);
minStack.push(1);
console.log(minStack.minStack, minStack.min()); // output: [ 3, 3, 2, 1 ] 1
minStack.pop();
minStack.pop();
minStack.push(0);
console.log(minStack.minStack, minStack.min()); // output: [ 3, 3, 0 ] 0
栈的压入弹出序列
1. 题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如序列 1、2、3、4、5 是某栈的压栈序列,序列 4、5、3、2、1 是该压栈序列对应的一个弹出序列,但 4、3、5、1、2 就不可能是该压栈序列的弹出序列。
2. 思路分析
栈的题目还是借助“辅助栈”。大体思路如下:
- 将入栈序列的元素依次入辅助栈
- 检查辅助栈顶元素和弹栈序列栈顶元素是否一致:
- 元素一致,弹出辅助栈元素,弹栈序列指针后移
- 不一致,回到第一步
需要注意的是,过程中的边界条件检查(多试试几种情况)。除此之外,由于 js 不提供指针运算,所以用标记下标的方法代替指针。
3. 代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* 获得栈顶元素
* @param {Array} stack
*/
function getStackTop(stack) {
if (!Array.isArray(stack)) {
return null;
}
if (!stack.length) {
return null;
}
return stack[stack.length - 1];
}
/**
* 第二个参数是否是该栈的弹出顺序
* @param {Array} pushOrder
* @param {Array} popOrder
* @return {Boolean}
*/
function check(pushOrder, popOrder) {
if (
!pushOrder.length ||
!popOrder.length ||
pushOrder.length !== popOrder.length
) {
return false;
}
const stack = []; // 辅助栈
let i = 0,
j = 0; // i: 压入序列指针; j: 弹出序列指针
while (j < popOrder.length) {
for (
;
i < pushOrder.length && popOrder[j] !== getStackTop(stack);
++i
) {
stack.push(pushOrder[i]);
}
if (popOrder[j] !== getStackTop(stack)) {
return false;
}
stack.pop();
++j;
}
return true;
}
/**
* 以下是测试代码
*/
console.log(check([1, 2, 3, 4], [4, 3, 2, 1]));
console.log(check([1, 2, 3, 4, 5], [4, 5, 3, 2, 1]));
console.log(check([1, 2, 3, 4, 5], [4, 3, 5, 1, 2]));
本文由作者按照 CC BY 4.0 进行授权