leetcode刷题之队列简单总结

239. 滑动窗口最大值

public class MyQueue{  //构建自己的队列及相关方法,add,poll,peek
 	Deque<Integer> deque=new LinkedList<>();
 	void add(int val) {
 		while(!deque.isEmpty()&&val>deque.getLast()) {//保证队列按照从大到小的顺序,
 			deque.removeLast();
 		}
 		deque.add(val);//deque.add(val)答案是这样写得(注意栈和队列之间的区别,不能用push,应该用add)
 	}
 	void poll(int val) {//在弹出队列头时,比较当前要弹出的数值是否等于队列头,如果相等就弹出,因为有可能要求弹出的数组下标对应的数值之前已经被弹出了
 		if(!deque.isEmpty()&&val==deque.peek()) {
 			deque.poll();
 		}
 	}
 	int peek() {
 		return deque.peek();//返回队列头,队列头始终是这一个队列的最大值
 	}
}
public class MaxSlidingWindow {	
 	public int[] maxSlidingWindow(int[] nums,int k) { 		
 		if(nums.length<=0)
 			return null;
 		if(nums.length==1)//一定不要忘了这种情况,因为是返回一个数组类型
 			return nums;
 		int[] res=new int[nums.length+1-k];//因为一个窗口是k个大小,一共会有数组长度+1减k的大小
 		int num=0;
 		MyQueue myqueue=new MyQueue();
 		for(int i=0;i<k;i++) {
 			myqueue.add(nums[i]);   //先把第一个窗口加入队列
 		}
 		res[num++]=myqueue.peek();//不要忘记把第一个窗口的最大值加入结果数组中
 		for(int i=k;i<nums.length;i++) {//逐步推进窗口前进
 			myqueue.poll(nums[i-k]);//判断如何删掉窗口左端口的数(也就是删除队列头)
 			myqueue.add(nums[i]);//判断如何加入窗口右端口的数(也就是添加队列尾)
 			res[num++]=myqueue.peek();//每前进一步,就记录该窗口的最大值。
 		}
 		return res;	
 	}
}

思路简述

运用了单调队列的思想方法,也就是队列是递增或者是递减的,这样利于寻找每个窗口里的最大值。

在逐步用窗口检测已给数组的时候,需要另外维护这样一个单调队列。这个队列是单调递减的,队头是最大值。
重点在于这个队列不一定要维护整个数组,而是维护窗口大小内最有可能成为最大值的就可以。也就是说,这个队列的大小就在1-k(给定的窗口大小)。
那么具体怎么维护吗?也就是在队列加入新元素进行判断,如果之前队列里的旧元素比新元素小,那么就直接删去那些旧元素,让能者上位。
因为在被检测数组的眼中,是将窗口大小的框逐步向前移动,那么主要过程就是,删除框左端的数组元素,并增加框右端后面的数据元素。然后每次都要记录一下这次框里的最大值。
删除元素,也就是将队列头的元素抛出,但是这里需要注意,因为之前队列添加新元素时发生的新旧元素的对比,原定的数组下标的元素很有可能已经被抛出了,所以需要判断一下此时队列头和数组里需要删除的元素是否一致,如果一致再删除队列头。

注意,每次移动窗口时,单调队列的判断顺序应该是:
1.判断是否移除队头
2.增加队尾
3.返回队头(也就是返回此次窗口最大值)

347. 前K个高频元素

public int[] topKFrequent(int[] nums,int k) {
	int[] result=new int[k];
	HashMap<Integer,Integer> map=new HashMap<>();
	for(int num:nums) {
		map.put(num, map.getOrDefault(num, 0)+1);
	}
	Set<Map.Entry<Integer,Integer>> entries=map.entrySet();  //Map.Entry<Integer,Integer>是一种类型,map.entrySet是返回这种类型的集合
    // 根据map的value值正序排,相当于一个小顶堆
    PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
    for (Map.Entry<Integer, Integer> entry : entries) {
        queue.offer(entry);
        if (queue.size() > k) {
            queue.poll();
        }
    }
    for (int i = k - 1; i >= 0; i--) {
        result[i] = queue.poll().getKey();
    }
    return result;
}

思路简述

这个题的关键就是维护一个长度为K的优先级队列。(要熟练应用这种思想,只记录必要个数的元素就行,不用全部维护) 解题的步骤就是记录每个数组元素的出现次数,然后按照次数对数组元素进行排序,最后返回前K个元素。
先用map来存储,key是数组元素,value是该元素出现的次数。
然后用优先级队列来存储map。也就是把map.entrySet里的元素逐个弹入队列中,队列会自动排序。然后如果队列里的元素超过了k,那么就弹出队头(这个优先级队列设置的是从小到大,这样弹出比较方便,也就是每次弹出去的队头都是出现次数最少的数组元素)
最后再把队列里存储的entryset里的key都转移到数组中就可以了。因为可以按任意顺序返回答案,所以数组里的顺序就不是很重要了。

关键点

1.维护一个长度为K的优先级队列。(要熟练应用这种思想,只记录必要个数的元素就行,不用全部维护)
1.单调队列的应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值