实现括号匹配校验和滑动窗口最大值。
先理解原理和示例,再练习完整口述与追问。
回答要点
括号匹配用栈:左括号入栈,右括号时弹出栈顶并检查是否配对,遍历结束栈必须为空。滑动窗口最大值用单调递减双端队列保存下标:新元素入队前弹出所有不大于它的队尾,队头下标滑出窗口时移除,队头即当前窗口最大值,整体 O(n)。
原理拆解
括号的“最近未闭合的左括号必须先闭合”正好是后进先出,所以用栈。只处理三种括号,其他字符跳过;提前遇到右括号而栈为空时 pop() 返回 undefined,不等于任何左括号,直接返回 false。
滑动窗口中,如果一个元素比它左边的元素更大,左边的那个在之后的任何窗口中都不可能成为最大值,可以丢弃,因此队列从头到尾保持递减。每个下标最多入队、出队各一次,所以是线性时间。JavaScript 数组的 shift 是 O(n),用 head 指针代替队头出队,保持整体线性。k 不合法时抛出 RangeError,比返回空数组更容易发现调用错误。
示例与推演
function isValidBrackets(text) {
const pairs = { ')': '(', ']': '[', '}': '{' }
const stack = []
for (const char of text) {
if (char === '(' || char === '[' || char === '{') stack.push(char)
else if (char === ')' || char === ']' || char === '}') {
if (stack.pop() !== pairs[char]) return false
}
}
return stack.length === 0
}
function maxSlidingWindow(nums, k) {
if (!Number.isInteger(k) || k < 1 || k > nums.length) {
throw new RangeError('k 必须是 1 到数组长度之间的整数')
}
const deque = []
let head = 0
const result = []
for (let i = 0; i < nums.length; i++) {
while (deque.length > head && nums[deque[deque.length - 1]] <= nums[i]) deque.pop()
deque.push(i)
if (deque[head] <= i - k) head++
if (i >= k - 1) result.push(nums[deque[head]])
}
return result
}
推演:maxSlidingWindow([1, 3, -1, -3, 5, 3, 6, 7], 3) 得到 [3, 3, 5, 5, 6, 7];在 i = 4 时,5 入队前把 -3、-1、3 全部弹出,队头变为 5。
易错点
括号题只比较数量而不检查顺序,会把 ([)] 误判为合法;滑动窗口中队列存值而不是下标,就无法判断队头是否已滑出窗口。
参考回答可直接练习口述
括号匹配用栈,左括号入栈,遇到右括号就弹出栈顶看是否配对,最后栈要为空。滑动窗口最大值用单调递减的双端队列存下标:新元素进来前把队尾不大于它的都弹掉,因为它们以后不可能是最大值;队头下标滑出窗口就移除;窗口形成后队头就是最大值。每个元素进出队列各一次,所以是 O(n),JS 里用 head 指针避免 shift 的开销。