01.用栈实现队列
思路:使用两个栈实现队列功能
class MyQueue {
private stackIn:number[];
private stackOut:number[];
constructor() {
this.stackIn = []
this.stackOut = []
}
push(x: number): void {
this.stackIn.push(x)
}
pop(): number {
this.stackOut.push(...this.stackIn)
this.stackIn = []
let tmp = this.stackOut.splice(0,1)
return tmp[0]
}
peek(): number {
this.stackOut.push(...this.stackIn)
this.stackIn = []
return this.stackOut[0]
}
empty(): boolean {
console.log(this.stackIn, this.stackOut)
if (this.stackIn.length == 0 && this.stackOut.length == 0) return true
return false
}
}
02.用队列实现栈
思路:。。。
class MyStack {
private queue:number[];
constructor() {
this.queue = []
}
push(x: number): void {
this.queue.push(x)
}
pop(): number {
return this.queue.splice(this.queue.length - 1)[0]
}
top(): number {
return this.queue[this.queue.length - 1]
}
empty(): boolean {
if (this.queue.length == 0) return true
return false
}
}
/**
* Your MyStack object will be instantiated and called as such:
* var obj = new MyStack()
* obj.push(x)
* var param_2 = obj.pop()
* var param_3 = obj.top()
* var param_4 = obj.empty()
*/
03.有效的括号
思路:利用栈后入先出的特性,遍历字符串
function isValid(s: string): boolean {
let stack:string[] = []
for (let i = 0; i < s.length; i++) {
switch (s[i]) {
case '(': stack.push(')');break
case '{': stack.push('}');break
case '[': stack.push(']');break
default: if (s[i] != stack.pop())return false
}
}
return stack.length == 0
};
04.删除字符串中的所有相邻重复项
思路:利用栈后入先出的特性,与栈最后一个字符做对比,相同则去除最后一位,否则,将该字符加入栈中
function removeDuplicates(s: string): string {
let stack:string[] = []
for (let i = 0; i < s.length; i++) {
if (s[i] == stack[stack.length - 1]) {
stack.pop()
} else {
stack.push(s[i])
}
}
return stack.join('')
};
05.逆波兰表达式求值
思路:当遇到运算符时,取出栈中最后两位计算,并将结果推入栈中
function evalRPN(tokens: string[]): number {
let stack:number[] = []
let tmp
for (let i = 0; i < tokens.length; i++) {
switch (tokens[i]) {
case '+' :
tmp = stack.pop()
stack.push(tmp! + stack.pop()!)
break;
case '-' :
tmp = stack.pop()
stack.push(stack.pop()! - tmp!)
break;
case '*' :
stack.push(stack.pop()! * stack.pop()!)
break
case '/' :
tmp = stack.pop()
stack.push(Math.trunc(stack.pop()! / tmp!))
break
default:
stack.push(+tokens[i])
break
}
}
return stack.pop()
};
06. 滑动窗口最大值*
思路:使用单调队列。在本题中为单调递减队列。入列的条件:大于队尾元素或者队列为空。出列:当窗口的的第一个值等于队头元素时出列。
单调队列真是一种让人感到五味杂陈的数据结构,它的维护过程更是如此.....就拿此题来说,队头最大,往队尾方向单调......有机会站在队头的老大永远心狠手辣,当它从队尾杀进去的时候,如果它发现这里面没一个够自己打的,它会毫无人性地屠城,把原先队里的人头全部丢出去,转身建立起自己的政权,野心勃勃地准备开创一个新的王朝.....这时候,它的人格竟发生了一百八十度大反转,它变成了一位胸怀宽广的慈父!它热情地请那些新来的“小个子”们入住自己的王国......然而,这些小个子似乎天性都是一样的——嫉妒心强,倘若见到比自己还小的居然更早入住王国,它们会心狠手辣地找一个夜晚把它们通通干掉,好让自己享受更大的“蛋糕”;当然,遇到比自己强大的,它们也没辙,乖乖夹起尾巴做人。像这样的暗杀事件每天都在上演,虽然王国里日益笼罩上白色恐怖,但是好在没有后来者强大到足以干翻国王,江山还算能稳住。直到有一天,闯进来了一位真正厉害的角色,就像当年打江山的国王一样,手段狠辣,野心膨胀,于是又是大屠城......历史总是轮回的。
---- leetcode用户:虫子的世界
function maxSlidingWindow(nums: number[], k: number): number[] {
class MonoQueue {
private queue:number[];
constructor () {
this.queue = []
}
public enqueue (value:number) {
let back: number | undefined = this.queue[this.queue.length - 1]
while (back != undefined && back < value) {
this.queue.pop()
back = this.queue[this.queue.length - 1]
}
this.queue.push(value)
}
public dequeue (value:number) {
let top:number | undefined = this.top()
if (top != undefined && top == value) {
this.queue.shift()
}
}
public top ():number | undefined{
return this.queue[0]
}
}
const helperQueue: MonoQueue = new MonoQueue();
let i: number = 0,
j: number = 0;
let resArr: number[] = [];
while (j < k) {
helperQueue.enqueue(nums[j++]);
}
resArr.push(helperQueue.top()!);
while (j < nums.length) {
helperQueue.enqueue(nums[j]);
helperQueue.dequeue(nums[i]);
resArr.push(helperQueue.top()!);
j++, i++;
}
return resArr;
};
07.前 K 个高频元素
思路:使用map记录元素及其出现次数。然后将map结构成数组,降序排序并且截取前k个
function topKFrequent(nums: number[], k: number): number[] {
let frequentMap:Map<number, number> = new Map()
for (let num of nums) {
frequentMap.set(num, (frequentMap.get(num) || 0) + 1)
}
console.log(...frequentMap.entries())
return [...frequentMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, k).map(i=>i[0])
};