一、 理论
1. 栈简介
- 一个 先进后出 的数据结构
- js中没有栈,但可以用Array实现队列的所有功能
// stack
const stack = []
stack.push(1)
stack.push(2)
const item1 = stack.pop()
const item2 = stack.pop()
2. 栈的应用场景
- 需要 后进先出 的场景
2.1 十进制转二进制
- 后出来的余数反而排在前面
- 把余数一次入栈,再出栈
2.2 有效的括号
((((())))) -- valid
()()()() -- valid
((((((() -- invalid
((()(()))) -- valid
- 越靠后的左括号,对应的右括号越靠前
- 左括号入栈、右括号出栈,最后栈空了就是合法的
2.3 函数调用堆栈
function greeting() {
sayHi()
}
function sayHi() {
return 'Hi!'
}
greeting()
- 最后调用的函数最先执行完
- js解释器使用栈来控制函数的调用顺序
二、刷题
1. 有效的括号(20)
1.1 题目描述
- 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效
- 有效字符串需满足:
- 左括号必须用相同类型的右括号闭合
- 左括号必须以正确的顺序闭合
1.2 解题思路
- 越靠后的左括号,对应的右括号越靠前
1.3 解题步骤
- 新建栈
- 扫描字符串
- 遇到左括号就入栈
- 遇到和栈顶匹配的右括号则出栈
- 不匹配则false
- 最后栈空true
function isValid(s) {
if(s.length % 2 == 1) return false
const stack = []
for(let i = 0; i < s.length; i++) {
let c = s[i]
if(c == '(' || c == '{' || c == '[') {
stack.push(c)
} else {
const t = stack[stack.length-1]
if(
(t == '(' && c == ')') ||
(t == '{' && c == '}') ||
(t == '[' && c == ']')
) {
stack.pop()
} else {
return false
}
}
}
return stack.length == 0
}
1.4 时间复杂度&空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
2. 函数调用堆栈(前端与栈)
code part
// callStack
const func1 = () => {
func2()
}
const func2 = () => {
func3()
}
const func3 = () => {}
func1()
3. 二叉树的前序遍历(144)
使用栈模拟递归、改写递归
3.1 题目描述
- 给你二叉树的根节点 root ,返回它节点值的 前序 遍历
1.2 解题
function preorderTraversal(root) {
const res = []
const stack = []
if(root) stack.push(root)
while(stack.length) {
const n = stack.pop()
res.push(n.val)
if(n.right) stack.push(n.right)
if(n.left) stack.push(n.left)
}
return res
}
1.4 时间复杂度&空间复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
三、总结 -- 技术要点
- 栈是一个后进先出的数据结构
- js中没有栈,但可以用Array实现栈的所有功能
- 栈的常用操作:push pop stack[stack.length-1]
四、思考题
1. 实现栈类
class Stack {
constructor() {
this.stack = []
}
push(c) {
this.stack.push(c)
}
pop() {
return this.stack.pop()
}
peek() {
return this.stack[this.stack.length-1]
}
}
2. 实现ten2Two函数
function ten2Two(num) {
const stack = []
while(num) {
stack.push(num % 2)
num = parseInt(num/2)
}
return stack.reverse().join('')
}