赞
踩
做完最小栈的题能更好的理解这道题
鄙人想到了开辟空间来保存最小值,使用的HashMap;K神用的是栈+逻辑优化
class MinStack { private Stack<Integer> stack; private Stack<Integer> min_stack; public MinStack() { stack = new Stack<>(); min_stack = new Stack<>(); } public void push(int val) { stack.push(val); if (min_stack.isEmpty() || val <= min_stack.peek()) min_stack.push(val); } public void pop() { if (stack.pop().equals(min_stack.peek())) min_stack.pop(); } public int top() { return stack.peek(); } public int getMin() { return min_stack.peek(); } }
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums.length == 0 || k == 0) return new int[0]; Deque<Integer> deque = new LinkedList<>(); int[] res = new int[nums.length - k + 1]; //左指针i,右指针j,为了保证每次循环的条件相同(即Carl哥讲的循环不变量),这里我们发现K写的代码右指针是从0开始遍历的,而左指针则是 0 - (k - 1) = 1 - k开始遍历的 for(int j = 0, i = 1 - k; j < nums.length; i++, j++) { // 删除 deque 中对应的 nums[i-1] if(i > 0 && deque.peekFirst() == nums[i - 1]) deque.removeFirst(); // 保持 deque 递减, // 循环停止 1.deque为空,表示nums[j]是当前最大的值,deque最后剩一个值 // 2.deque.peekLast() >= nums[j],表示小于等于deque中的剩余元素 while(!deque.isEmpty() && deque.peekLast() < nums[j]) deque.removeLast(); deque.addLast(nums[j]); // 记录窗口最大值 if(i >= 0) res[i] = deque.peekFirst(); } return res; } }
class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums.length == 0 || k == 0) return new int[0]; Deque<Integer> deque = new LinkedList<>(); int[] res = new int[nums.length - k + 1]; // 未形成窗口 for(int i = 0; i < k; i++) { while(!deque.isEmpty() && deque.peekLast() < nums[i]) deque.removeLast(); deque.addLast(nums[i]); } res[0] = deque.peekFirst(); // 形成窗口后 for(int i = k; i < nums.length; i++) { // i = k,i此时是右指针,左指针为0,右指针为 k - 1 //i = k 为新的右指针,原左指针为 i - k(多减了一个1),如果原左指针等于队列中最大值,则将队列中最大值删除(这步是判断被移除的元素是否是原来的窗口的最大值) if(deque.peekFirst() == nums[i - k]) deque.removeFirst(); //保持 deque 递减 while(!deque.isEmpty() && deque.peekLast() < nums[i]) deque.removeLast(); deque.addLast(nums[i]); // i - (k - 1) 是当前的左指针 res[i - k + 1] = deque.peekFirst(); } return res; } }
简单写一下堆的知识,便于理解优先队列,已经了解的朋友转到逻辑部分
参考8.1 堆 - Hello 算法 (hello-algo.com)
堆:是一种满足特定条件的完全二叉树,主要可分为两种类型
堆作为完全二叉树的一个特例,具有以下特性。
实际上,堆通常用于实现优先队列,大顶堆相当于元素按从大到小的顺序出队的优先队列。从使用角度来看,我们可以将“优先队列”和“堆”看作等价的数据结构。
堆的存储与表示
建堆操作
代码中见注解
class Solution { public int[] topKFrequent(int[] nums, int k) { //key为num,value为出现的次数 Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>(); for (int num : nums) { occurrences.put(num, occurrences.getOrDefault(num, 0) + 1); } // int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数 //PriorityQueue是优先队列,按照比较器(Comparator)的逻辑来比较元素 //若要实现升序排序,当第一个参数 < 第二个参数时返回负数,相等时返回 0; //若要实现降序排序,当第一个参数 > 第二个参数时返回负数,相等时返回 0。 //也可以简单理解成 return出的参数和compare中参数相对位置一致是升序,相反是降序 //这里是 第一种情况升序 PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() { public int compare(int[] m, int[] n) { return m[1] - n[1]; } }); //entrySet()放回map中的每个键值对组成的集合 for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) { int num = entry.getKey(), count = entry.getValue(); //如果queue大小已经等于k,判断队列第一个元素的[1]也就是最小出现频率是否大于当前count if (queue.size() == k) { //当前count > peek()[1],弹出队首元素,将当前数字及频率创建数组添加到queue中 if (queue.peek()[1] < count) { queue.poll(); queue.offer(new int[]{num, count}); } } else { queue.offer(new int[]{num, count}); } } //创建大小为k的数组,保存最后结果 int[] ret = new int[k]; for (int i = 0; i < k; ++i) { ret[i] = queue.poll()[0]; } return ret; } }
public List<Integer> topKFrequent(int[] nums, int k) { List<Integer>[] bucket = new List[nums.length + 1]; Map<Integer, Integer> frequencyMap = new HashMap<Integer, Integer>(); for (int n : nums) { frequencyMap.put(n, frequencyMap.getOrDefault(n, 0) + 1); } for (int key : frequencyMap.keySet()) { int frequency = frequencyMap.get(key); if (bucket[frequency] == null) { bucket[frequency] = new ArrayList<>(); } bucket[frequency].add(key); } List<Integer> res = new ArrayList<>(); //出现频次高的在列表后面,使用倒序遍历, //停止条件为 pos >= 0,有可能数组里面数字的种类凑不齐k个数 //res.size() < k表示res已经记录了出现频次最高的k个数字 for (int pos = bucket.length - 1; pos >= 0 && res.size() < k; pos--) { //不为空的添加到列表中 if (bucket[pos] != null) { res.addAll(bucket[pos]); } } return res; }
451. 根据字符出现频率排序 - 力扣(LeetCode)
(bucket[pos]);
}
}
return res;
}
#### 相似习题
[692. 前K个高频单词 - 力扣(LeetCode)](https://leetcode.cn/problems/top-k-frequent-words/description/)
[451. 根据字符出现频率排序 - 力扣(LeetCode)](https://leetcode.cn/problems/sort-characters-by-frequency/)
显然这两道题,区别在于存储出现频率时,key为String/Character,value为Integer,其他的逻辑部分大差不差,具体实现不同需要自己补充了解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。