算法训练营第十三天|239. 滑动窗口最大值、347.前 K 个高频元素

47 阅读1分钟

第十二天是周日休息

239. 滑动窗口最大值

单调队列经典题

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        int[] res = new int[n - k + 1];
        Deque<Integer> q = new LinkedList<>(); // q里存这个元素在nums中的索引
        for(int i = 0; i < n; i++){
            // 维护队列的有效性。如果队列不为空,并且队列首部的索引对应的元素已经不在滑动窗口内,则将其从队列中删除。
            if(!q.isEmpty() && q.getFirst() < i - k + 1){
                q.pollFirst();
            }

            // 保证队列中的元素是非增的
            while(!q.isEmpty() && nums[q.getLast()] < nums[i]){
                q.pollLast();
            }

            q.addLast(i);

            if(i >= k - 1){ // 当遍历的元素足够多,能够构成一个完整的滑动窗口时
                res[i - k + 1] = nums[q.getFirst()];
            }
        }
        return res;
    }
}

347. 前 K 个高频元素

Java中优先队列是用小根堆实现的

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer, Integer> valToFreq = new HashMap<>(); // <nums中的元素,该元素出现的频率>
        for(int num : nums){
            valToFreq.put(num, valToFreq.getOrDefault(num, 0) + 1);
        }

        PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>((entry1, entry2) ->
            {return entry1.getValue().compareTo(entry2.getValue());
        }); // 队列按照键值对中的值(元素出现频率)从小到大排序

        for(Map.Entry<Integer, Integer> entry : valToFreq.entrySet()){
            pq.offer(entry);
            if(pq.size() > k){
                // 弹出最小元素,维护队列内是k个频率最大的元素
                pq.poll();
            }
        }

        int[] res = new int[k];
        for(int i = k - 1; i >= 0; i--){
            // res 数组中存储前k个最大元素
            res[i] = pq.poll().getKey();
        }

        return res;
    }
}