239. 滑动窗口最大值
链接
题目链接
文章链接
第一想法
看到这道题,发现也是取窗口最大的,想法还是单调队列,不过有些不同,先需要比较初始状态下的滑动窗口里面的最大值,并用stack存储下标(从大到小),则stack[0]的位置就是当前滑动窗口的最大值,代码如下:
let stack:number[]=[] //单调队列
let res:number[]=[] //存放最终结果
for(let i=0;i<k;i++){ //初始滑动窗口 这里类似单调队列
while(stack.length>0&&nums[stack[stack.length-1]]<nums[i]){//这里比较的是下标对应nums数值的大小
stack.pop()
}
stack.push(i)//存储下标
}
res.push(nums[stack[0]]) //将当前滑动窗口的最大值存储
之后开始对窗口进行滑动,且stack[0]一定是滑动窗口的最大值的下标,代码如下:
for(let i=k;i<nums.length;i++){
if(i-k>=stack[0]) stack.shift(); //这里 是防止这种情况 [100,4,33,1] 当k=3时,且滑动窗口为下标1 2 3时,stack[0]仍是下标0的情况,这里判断i-k>stack[0]是如果滑动
while(stack.length>0&&nums[stack[stack.length-1]]<nums[i]){
stack.pop()
}
stack.push(i)
res.push(nums[stack[0]])//将当前滑动窗口的最大值存储
}
return res
完整代码如下:
function maxSlidingWindow(nums: number[], k: number): number[] {
let stack:number[]=[]
let res:number[]=[]
for(let i=0;i<k;i++){
while(stack.length>0&&nums[stack[stack.length-1]]<nums[i]){
stack.pop()
}
stack.push(i)
}
res.push(nums[stack[0]])
for(let i=k;i<nums.length;i++){
if(i-k>=stack[0]) stack.shift();
while(stack.length>0&&nums[stack[stack.length-1]]<nums[i]){
stack.pop()
}
stack.push(i)
res.push(nums[stack[0]])
}
return res
};
看完文章后的想法
文章的想法和我的想法是一致,只不过有点区别,他是维护元素而我维护的是下标,同时它先构造了一个队列有助于我们理解,代码如下:
function maxSlidingWindow(nums: number[], k: number): number[] {
class Queue{
queue:number[];
constructor(){
this.queue=[]
}
//入队
public enqueue(value:number):void{
while(this.queue.length>0&&this.queue[this.queue.length-1]<value){
this.queue.pop()
}
this.queue.push(value)
}
//出队,也就是我上方代码中的i-k>=stack[0]这个条件
public dequeue(value:number):void{
if(value===this.queue[0]) this.queue.shift()
}
//获取最大元素
public top():number{
return this.queue[0]
}
}
let stack:Queue=new Queue();
let res:number[]=[]
for(let i=0;i<k;i++){
stack.enqueue(nums[i])
}
res.push(stack.top())
for(let i=k,j=0;i<nums.length;i++,j++){
stack.dequeue(nums[j]) //查看stack[0]是否要出队
stack.enqueue(nums[i])
res.push(stack.top())
}
return res
};
思考
这道题属于hard,确实很难,但是ts/js没有栈和队列这个概念,数组可以完全模拟栈和队列,所以构造一个类是比较思路清晰一点,完整详细的讲解请看代码随想录中的讲解,很细,这道题得多次回顾查看。
347. 前 K 个高频元素
链接
文章链接
题目链接
第一想法
我首先想到的就是利用哈希表,key值为nums的元素,value为出现的次数,之后再转变为arr,通过sort方法按照次数从大到小排列,之后取前k个元素,代码如下:
function topKFrequent(nums: number[], k: number): number[] {
let map:Map<number,number>=new Map()
let res:number[]=[]
for(let i=0;i<nums.length;i++){
map.set(nums[i],1+(map.get(nums[i])||0))
}
let arr:number[][]=Array.from(map)
arr.sort((a,b)=>b[1]-a[1])
for(let i=0;i<k;i++){
res.push(arr[i][0])
}
return res
};
看完文章后的想法
文章利用的是小顶堆,大小为k,但是ts/js里面没有堆这个概念,所以文章中也是用来sort这个函数,这是文章中的ts代码:
function topKFrequent(nums: number[], k: number): number[] {
const countMap: Map<number, number> = new Map();
for (let num of nums) {
countMap.set(num, (countMap.get(num) || 0) + 1);
}
// tS没有最小堆的数据结构,所以直接对整个数组进行排序,取前k个元素
return [...countMap.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, k)
.map(i => i[0]);
};
思考
代码随想录中我看到了也有自己构造小顶堆的,如果是我单独自己的话,估计很难模拟出来,但是利用小顶堆这个问题的思路我是搞懂了的,总体上说是不难的。但是手写小顶堆得去练习一下。
今日总结
今日总共两道题,第一道比较难,第二道不难,但是如果手写小顶堆的话就比较难了,用时2.5小时。