Carl代码随想录算法训练营-Day 13-239. 滑动窗口最大值、347.前 K 个高频元素

摘要

算法训练营日常学习记录。本文分享了两道leetcode题目:239. 滑动窗口最大值和347.前 K 个高频元素的解题方法,详细分析了思路,并给出了具体的Java代码实现。

239、滑动窗口最大值

LeetCode题目链接

思路分析

这道题,题意大概是是在一个数组中放入一个定长的滑动窗口,随着滑动窗口的移动,记录移动过程中滑动窗口中的最大元素的值。
因此我们不难想到,或许运用一个优先队列PriorityQueue就可以很轻松地做到挑选出滑动窗口中的最大值。但是在本题中,滑动窗口会并入新的元素,同时推出一个旧元素,如果用优先队列,则需要进行搜索,时间复杂度较低。而且由于我们只需要维护滑动窗口中的最大元素值,优先队列维护全队列的排序的做法,就显得浪费性能了。
基于以上两点,我们可以设计一个单调队列MotonicQueue,它除了具备常规队列的offerpoll操作以外,还应具备一个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 个高频元素

LeetCode题目链接

思路分析

这道题可以直接使用优先队列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;
        }

总结和思考

以上就是今天的算法学习记录,我们通过分析思路和实现代码的方式,解决了这道题目。希望对大家的算法学习有所帮助,谢谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值