代码随想录算法训练营第十三天| 239 滑动窗口最大值 347 前 K 个高频元素

目录

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)

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值