摘要
算法训练营日常学习记录。本文分享了两道leetcode题目:239. 滑动窗口最大值和347.前 K 个高频元素的解题方法,详细分析了思路,并给出了具体的Java代码实现。
239、滑动窗口最大值
思路分析
这道题,题意大概是是在一个数组中放入一个定长的滑动窗口,随着滑动窗口的移动,记录移动过程中滑动窗口中的最大元素的值。
因此我们不难想到,或许运用一个优先队列PriorityQueue
就可以很轻松地做到挑选出滑动窗口中的最大值。但是在本题中,滑动窗口会并入新的元素,同时推出一个旧元素,如果用优先队列,则需要进行搜索,时间复杂度较低。而且由于我们只需要维护滑动窗口中的最大元素值,优先队列维护全队列的排序的做法,就显得浪费性能了。
基于以上两点,我们可以设计一个单调队列MotonicQueue
,它除了具备常规队列的offer
和poll
操作以外,还应具备一个getMaxValue
操作,而且其时间复杂度为O(1)
。
分析一下MotonicQueue
的实现细节。底层数据结构可以采用一个自定义队列,也可以直接使用一个链表LinkedList
类。
offer
操作。为了保证最大元素在队口(poll
操作立刻出队的元素),要维持这个队列从对口到队尾永远是一个单调递减的序列。当要offer
的元素大于队尾元素时,则要将队尾元素连续剔除,直到offer
元素不大于队尾元素。
poll
操作。由于队口永远是最大元素,但不一定是我们的滑动窗口滑动时要弹出的元素,因此要比较一下,只有当需要poll
的元素与队口元素相等时才将其弹出。
代码实现
public int[] maxSlidingWindow(int[] nums, int k) {
int[] ans = new int[nums.length - k + 1];
MotonicQueue queue = new MotonicQueue();
for (int i = 0; i < k; i++) {
queue.offer(nums[i]);
}
ans[0] = queue.getMaxValue();
for (int i = 1; i <= nums.length - k; i++) {
queue.poll(nums[i - 1]);
queue.offer(nums[i + k - 1]);
ans[i] = queue.getMaxValue();
}
return ans;
}
class MotonicQueue {
private final LinkedList<Integer> list;
public MotonicQueue() {list = new LinkedList<Integer>();}
public void poll(int val) {
if (!list.isEmpty() && list.peekFirst() == val) {
list.pollFirst();
}
}
public void offer(int val) {
while (!list.isEmpty() && list.peekLast() < val) {
list.pollLast();
}
list.addLast(val);
}
public int getMaxValue() {
if (list.isEmpty()) {return Integer.MIN_VALUE;}
return list.peekFirst();
}
}
347、前 K 个高频元素
思路分析
这道题可以直接使用优先队列PriorityQueue
类。在通过HashMap
对数组中的所有元素出现次数计数之后,遍历HashMap
,把键值对全部加入优先队列。优先队列PriorityQueue
的排序规则要设置成按照出现次数排序。
完成加入工作之后,只要弹出前k个元素即可。
代码实现
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.merge(num, 1, Integer::sum);
}
PriorityQueue<int[]> pq = new PriorityQueue<>((x, y) -> y[1] - x[1]);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
pq.add(new int[]{entry.getKey(), entry.getValue()});
}
int[] ans = new int[k];
for (int i = 0; i < ans.length; i++) {
ans[i] = pq.poll()[0];
}
return ans;
}
总结和思考
以上就是今天的算法学习记录,我们通过分析思路和实现代码的方式,解决了这道题目。希望对大家的算法学习有所帮助,谢谢阅读!