代码随想录算法训练营第十三天| 239 滑动窗口最大值 347 前 K 个高频元素
目录
239 滑动窗口最大值
方法一
每次滑动窗口移动都删除队头元素(如果该元素在add中未被删除),如果队尾元素比当前元素小则进行删除操作,确保当前元素为队列中最小值后将当前元素入队,则myQueue中的元素单调递减排序,队头为最大值,队尾为最小值,并将此时的队头元素加入到res数组中,最后返回res数组。
class MyQueue{
Deque<Integer>deque = new LinkedList<>();
void poll(int val){
if(!deque.isEmpty() && val == deque.peek()){//移除队头的元素,需要判断val是否等于deque.peek(),因为nums[i - k]的值可能在add()操作时被删除
deque.poll();
}
}
void add(int val){
while(!deque.isEmpty() && val > deque.getLast()){
deque.removeLast();//去除小于队列中val的元素,保证队列单调递减
}
deque.add(val);
}
int peek(){//取出队头元素(整个队列的最大值)
return deque.peek();
}
}
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
MyQueue myQueue = new MyQueue();
int len = nums.length - k + 1;//结果中要返回一个长度为len的数组
int res[] = new int[len];
int cnt = 0;
for(int i = 0;i < k;i++){
myQueue.add(nums[i]);
}
res[cnt++] = myQueue.peek();
for(int i = k;i < nums.length;i++){
myQueue.poll(nums[i - k]);//去除最前面的元素
myQueue.add(nums[i]);//加入新元素
res[cnt++] = myQueue.peek();
}
return res;
}
}
时间复杂度O(n)
空间复杂度O(k)定义了辅助队列myQueue
方法二
用变量i遍历nums数组,每次滑动窗口移动都先进行判断确保队列的头节点下标大于i - k + 1否则进行删除。
如果队尾元素比nums[i]小则进行删除操作,确保nums[i]为队列中最小值后将i入队,队头则为最大值的下标,deque中存储的下标代表的元素按照单调递减顺序排列。将此时队头元素加入到res数组中。
完成遍历后返回res数组。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
ArrayDeque<Integer> deque = new ArrayDeque<>();
int len = nums.length - k + 1;
int res[] = new int[len];
int cnt = 0;
for(int i = 0;i < nums.length;i++){
while(!deque.isEmpty() && deque.peek() < i - k + 1){//确保队列的头节点在i - k + 1到i的范围内
deque.poll();
}
while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]){//确保队列单调,队头为整个队列的最大值
deque.pollLast();
}
deque.offer(i);//向队尾添加元素的下标
if(i >= k - 1){//此时应该向res中添加队列中最大值,即队头的值
res[cnt++] = nums[deque.peek()];
}
}
return res;
}
}
时间复杂度O(n)
空间复杂度O(k)定义了辅助队列deque
347 前 K 个高频元素
构建大顶堆存放nums中元素及其出现频数,最后弹出前k个频数较大的元素。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int res[] = 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();
PriorityQueue<Map.Entry<Integer,Integer>>queue = new PriorityQueue<>((o1,o2) -> o2.getValue() - o1.getValue());//根据map的value值,构建于一个大顶堆(o1 - o2: 小顶堆, o2 - o1 : 大顶堆)
for(Map.Entry<Integer,Integer> entry : entries){
queue.offer(entry);
}
for(int i = k - 1;i >= 0;i--){
res[i] = queue.poll().getKey();
}
return res;
}
}
时间复杂度O(nlogk) 每次堆操作花费了O(logk)的时间
空间复杂度O(n)
分类:
代码随想录算法训练营
标签:
算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?