栈
栈是一个 后进先出 的数据结构。JavaScript 中没有栈,但可以用 Array 实现栈的所有功能
const stack = [];
stack.push(1);
stack.push(2);
const item1 = stack.pop();
const item2 = stack.pop();
栈应用场景
需要 后进先出 (Last in First out
)的场景。日常生活中栈的应用:盘子、托盘、书堆等
- 十进制转二进制
- 判断字符串的括号是否有效
- 函数调用堆栈
- 文本编辑器、绘制程序中的撤销功能
- Web 浏览器所访问过的链接的历史记录
十进制转二进制
- 后出来的余数反而要排到前面
- 把余数依次入栈,然后再出栈,就可以谁啊虚拟余数倒序输出
有效的括号
- 越靠后的左括号,对应的有括号越靠前
- 左括号入栈,右括号出栈,最后栈空了就是合法的
函数调用堆栈
- 最后调用的函数,最后执行完
- JS 解释器使用栈来控制函数的调用顺序
function greeting() {
// ...
sayHi()
}
function sayHi() {
return 'Hi'
}
greeting()
20.有效的括号
输入输出
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效
输入:s = "()"
输出:true
输入:s = "()[]{}"
输出:true
输入:s = "(]"
输出:false
输入:s = "([)]"
输出:false
输入:s = "{[]}"
输出:true
题解
-
对于没有闭合的左括号而言,越靠后的左括号,对应的右括号越靠前
满足后进先出,考虑用栈
步骤
- 新建一个栈,扫描字符串,遇左括号入栈,遇到和栈顶括号类型匹配的有括号就出栈,类型不匹配直接判定为不合法,最后栈空了就合法,否则不合法
var isValid = function (s) {
if (s.length % 2 === 1) return false
const stack = []
for (let i = 0; i < s.length; i++) {
const 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
}
时间复杂度:O(n)
空间复杂度:O(n)
其他解法
var isValid = function (s) {
if (s.length % 2 === 1) return false
const stack = []
for (let ch of s) {
switch (ch) {
case '(':
case '[':
case '{':
stack.push(ch)
break
case '}':
if (stack.pop() !== '{') return false
break
case ']':
if (stack.pop() !== '[') return false
break
case ')':
if (stack.pop() !== '(') return false
break
}
}
return !stack.length
}
- 使用 Map 数据结构
var isValid = function (s) {
if (s.length % 2 === 1) return false
const stack = []
const map = new Map([
[')', '('],
[']', '['],
['}', '{'],
])
for (const ch of s) {
if (map.has(ch)) {
if (stack.pop() !== map.get(ch)) return false
} else {
stack.push(ch)
}
}
return !stack.length
}
思考题
ES6 封装栈
push
:添加一个元素到栈顶pop
:移除栈顶元素peek
:返回栈顶元素size
:返回栈里元素的个数
class Stack {
constructor() {
this.items = []
}
push(item) {
return this.items.push(item)
}
pop() {
return this.items.pop()
}
peek() {
return this.items[this.items.length - 1]
}
size() {
return this.items.length
}
}
十进制转二进制
- 除以二,得到的余数是从低到高的次序,而输出是从高到低,所以需要栈来反转
function baseConvert(num, base) {
const stack = []
const digits = '0123456789ABCDEF'
let res = ''
while (num > 0) {
rem = num % base
num = Math.floor(num / base)
stack.push(rem)
}
while (stack.length !== 0) {
res += digits[stack.pop()]
}
return res
}
baseConvert(25, 2)