Q22- code362-敲击计数器
实现思路
方法1: 队列
1 重点是每次 入队/出队列时,都进行超时检测,以优化内存占用
参考文档
代码实现
1 方法1: 队列 时间复杂度: O(n); 空间复杂度: O(n)
class HitCounter {
private q: number[]
constructor() {
this.q = []
}
hit(timestamp: number) {
this.clearOverTime(timestamp)
this.q.push(timestamp)
}
getHits(timestamp: number) {
this.clearOverTime(timestamp)
return this.q.length
}
// 移除超过5分钟的 过期敲击数据
clearOverTime(timestamp: number) {
while (this.q.length && timestamp - this.q[0] >= 300) {
this.q.shift()
}
}
}
Q23- code155-最小栈
实现思路
方法1: 单栈差值法
1 min: 永远保存的是 当前栈中的最小值
2 stack: 存入的和 当前最小值的差值:diff
3 在单栈差值法中,stack内最多只有一个负数,这是因为:
- 只有当 val < min 时,diff = val - min 才会是负数
- 当我们遇到一个负的diff时,会立即更新 min = val
- 只有当出现比当前min还小的新元素时,才会再次出现负数差值
- 此时上一个负数差值对应的元素一定还在栈中
即
每当一个新的负数差值入栈时,它就代表了当前的最小值。 同时,前一个代表最小值的负数差值会失去"最小值"的地位, 但它保存的信息仍然能用于恢复前一个最小值
方法2: [val, minVal]对象法
参考文档
代码实现
1 方法1: 单栈差值法 时间复杂度:O(1) 空间复杂度:O(n)
class MinStack {
private stack: number[] = [];
private min: number;
constructor() {
this.stack = [];
this.min = -1
}
push(val: number): void {
// 易错点1:要使用this.stack.length来让min不断初始化
// 这是因为 可能会存在 入栈又出栈为空再入栈值 的情况
if (!this.stack.length) {
this.min = val
}
const diff = val - this.min
// 如果当前元素值比当前最小值还要小,就要更新最小值
if (diff < 0) {
this.min = val
}
// 存入的是差值
this.stack.push(diff)
}
pop(): void {
const diff = this.stack.pop()
// 如果当前出栈值是负数,说明目前出栈的元素 就是最小值
// 出栈后需要更新min值指向 上一个最小值 oldMin
if (diff < 0) {
// 相当于:
// diff = this.newMin(val) - this.oldMin
// oldMin = this.newMin - diff && this.min = oldMin
this.min = this.min - diff
}
}
top(): number {
let diff = this.stack[this.stack.length - 1];
// 易错点2:如果diff小于0,说明此时就是最小值,不需要多余操作
return diff >= 0 ? diff + this.min : this.min;
}
getMin(): number {
return this.min
}
}
2 方法2: [val, minVal]对象法 时间复杂度:O(1) 空间复杂度:O(n)
class MinStack {
stack: Array<number[]>
constructor() {
this.stack = [[Number.MAX_VALUE, Number.MAX_VALUE]]
}
push(val: number): void {
this.stack.push([val, Math.min(this.getMin(), val)])
}
pop(): void {
this.stack.pop()
}
top(): number {
return this.stack[this.stack.length - 1][0]
}
getMin(): number {
return this.stack[this.stack.length - 1][1]
}
}
Q24- code232- 用栈实现队列
实现思路
方法1: 入队栈 + 出队栈
1 进入元素时,按序进入 入队栈;
2 弹出元素时,先依次把入队栈元素,【倒序】放入出队栈,再弹出队首元素
3 技巧:可以通过一个front变量,来简化出队栈为空时的 peek操作
参考文档
代码实现
1 方法1: 入队栈 + 出队栈 时间复杂度:平均 O(1) 空间复杂度:O(n)
class MyQueue {
in: number[];
out: number[];
front: number;
constructor() {
this.in = [];
this.out = [];
}
// O(1)
push(x: number): void {
// 通过front记录in的队首值,以简化out为空时的 peek查询
if (!this.in.length) this.front = x;
this.in.push(x);
}
// 平均 O(1),最坏情况 O(n)
pop(): number {
// 倒序把元素都 转移到out栈里
if (!this.out.length) {
while (this.in.length) this.out.push(this.in.pop());
}
return this.out.pop();
}
// O(1)
peek(): number {
if (!this.out.length) return this.front;
return this.out[this.out.length - 1];
}
// O(1)
empty(): boolean {
return !this.in.length && !this.out.length;
}
}