本文已参与「新人创作礼」活动,一起开启掘金创作之路。
关键词:操作受限的线性表 先进先出-队列 后进先出-栈
队列和栈不是全新的东西,只不过是多加了一些约束条件的数组或者链表而已。
队列和栈使用的场景都是在处理临时数据的时候,把数据按顺序处理,并在处理完成后销毁数据。
定义
相同点: 两个都是“操作受限”的线性表。
不同点:
栈:LIFO 后进先出,添加和删除的操作只能在一端进行。最典型的例子就是汉诺塔。
队列:FIFO 先入先出,添加和删除数据的操作分别是在两端进行的。拿号排队。
栈
队列
各个操作的复杂度
入栈、出栈、入队、出队,复杂度都是 O(1).
leetcode
【栈】20 有效的括号
function valid(s) {
const ss = s.split("");
if (ss.length % 2 !== 0) return false;
const diction = {
'}': '{',
']': '[',
')': '('
}
let cache = [];
for (let i = 0; i < ss.length; i++) {
if (i >= 1 && diction[ss[i]] === cache[cache.length - 1]) {
cache.pop()
} else {
cache.push(ss[i])
}
}
return !cache.length
}
【栈】71 简化路径
function simplifyPath(path) {
const paths = path.split('/');
let r = [];
for (let i = 0; i < paths.length; i++) {
if (paths[i] === '..') {
r.pop()
} else if (paths[i] && paths[i] !== '.') {
r.push(paths[i])
}
}
return '/' + r.join('/');
}
【队列】滑动窗口最大值
var maxSlidingWindow = function (nums, k) {
const res = [];
//分块与预处理
//左右分块
const n = nums.length;
const left = new Array(n);
const right = new Array(n);
for (let i = 0; i < n; i++) {
if (i % k === 0) {
right[i] = nums[i];
} else {
right[i] = Math.max(right[i - 1], nums[i]);
}
}
for (let i = n - 1; i >= 0; i--) {
if (i + 1 === n || (i + 1) % k === 0) {
left[i] = nums[i];
} else {
left[i] = Math.max(left[i + 1], nums[i]);
}
}
for (let i = 0; i <= n - k; i++) {
res.push(Math.max(left[i], right[i + k - 1]));
}
return res;
};
// 双端队列
var maxSlidingWindow = function (nums, k) {
const n = nums.length
if (n < 2 || k === 1) return nums
const ans = new Array(n - k + 1)
const q = []
for (let i = 0; i < n; i++) {
// 保证从大到小 如果前面数小则需要依次弹出,直至满足要求
while (q.length && nums[q[q.length - 1]] <= nums[i]) {
q.pop()
}
q.push(i) // 添加当前值对应的数组下标
if (q[0] <= i - k) {
q.shift()
}
if (i + 1 >= k) {
ans[i + 1 - k] = nums[q[0]]
}
}
return ans
};