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

文章介绍了如何使用单调队列解决滑动窗口最大值问题,以及利用优先队列求解数组中出现频率前k高的元素。在滑动窗口问题中,通过维护一个单调递减的队列,可以高效地找到每个窗口的最大值。对于高频元素问题,文章提出了使用优先队列(大顶堆)配合哈希映射来找出数组中出现频率最高的k个元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k **的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k个数字。滑动窗口每次只向右移动一位。

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

本题运用单调队列

单调队列:单调递减或单调递增的队列

设计单调队列的时候,pop,和push操作要保持如下规则:

  1. pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
  2. push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止

保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。

解题思路:

  1. 定义一个队列deque(用来存储对应的下标)
  2. 下标的范围应该是[i-k+1,i],所以需要满足的第一个条件就是deque.peek()<i-k+1
  3. 因为是一个单调队列,所以如果存入的数字比末尾的大,需要被弹出 nums[deque.peekLast()]<nums[i]
  4. 每当i符合一个k的范围,将deque.peek() 存入到结果当中
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        ArrayDeque<Integer> deque=new ArrayDeque<>();
        int[] reslut=new int[nums.length-k+1];
        int index=0;
        for(int i=0;i<nums.length;i++){
            while(!deque.isEmpty()&&deque.peek()<i-k+1){
                deque.poll();
            }
            while(!deque.isEmpty()&&nums[deque.peekLast()]<nums[i]){
                deque.pollLast();
            }
            deque.offer(i);
            if(i>=k-1){
                reslut[index++]=nums[deque.peek()];
            }
        }
        return reslut;
    }
}

Java中由ArrayDeque实现的接口

用Java创建ArrayDeque双端队列的方法:ArrayDeque<Type> animal = new ArrayDeque<>();

ArrayDeque方法:

  • 使用add(),addFirst()和addLast()添加元素
  • 使用 offer(),offerFirst()和offerLast()插入元素
  • 使用getFirst()和getLast()访问元素
  • 使用peek(),peekFirst()和peekLast()方法访问元素
  • 使用remove(),removeFirst(),removeLast()方法删除元素
  • 使用poll(),pollFirst()和pollLast()方法删除元素

347. 前 K 个高频元素

给你一个整数数组 nums和一个整数 k,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序返回答案。

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

该题使用优先队列

Java PriorityQueue类是一种队列数据结构实现,其中根据优先级处理对象。 默认情况下,优先级队列的对象按自然顺序排序

解题思路:

  1. 定义一个Map,其中Map键位num的值,值为num出现的次数
  2. 定义一个优先队列,将队列转换为Set集合,并将值和出现的次数添加到优先队列中,并且元素要按照从大到小排序
  3. 定义一个需要返回的数组,遍历弹出pq的值
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map=new HashMap<>();
        //定义Map键位num的值,值为num出现的次数。
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //定义一个优先队列
       PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2)->pair2[1]-pair1[1]);
        for(Map.Entry<Integer,Integer> entry:map.entrySet()){//大顶堆需要对所有元素进行排序
            pq.add(new int[]{entry.getKey(),entry.getValue()});
        }
        int[] reslut=new int[k];
        for(int i=0;i<k;i++){
            reslut[i]=pq.poll()[0];
        }
        return reslut;
    }
}

Java HashMap getOrDefault() 方法

getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。

getOrDefault() 方法的语法为:hashmap.getOrDefault(Object key, V defaultValue)

Java HashMap entrySet() 方法

entrySet() 方法返回映射中包含的映射的 Set 视图。

entrySet() 方法的语法为:hashmap.entrySet()

Lambda表达式 --> 函数式编程(函数编程思想)

  • 标准格式:(参数列表) -> {代码}

  • 格式说明:

    小括内的语法与传统方法参数列表一致,没有参数就留空,有多个参数就用逗号分隔

    【->】 是新引入的语法格式,代表指向动作

    大括号内的语法与传统方法体要求一致

  • 比较器案例

    List<Integer> list = new ArrayList<>();
            Collections.addAll(list,11,22,33,44,55);
            System.out.println("排序之前的集合:" + list);
            
            // 比较器的正常书写格式
            Collections.sort(list, new Comparator<Integer>() {
                @Override
                public int compare (Integer o1, Integer o2) {
                    return o2-o1;
                }
            });
     
            // Lambda表达式
            Collections.sort(list,(Integer o1, Integer o2)->{return o2-o1;});
            System.out.println("排序之后的集合:" + list);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值