当前位置: 首页 > article >正文

第一篇---滑动窗口最大值、前 K 个高频元素

第一篇---滑动窗口最大值、前 K 个高频元素

  • 滑动窗口最大值*
    • 题目:
    • 思路:
    • 代码:
  • 前 K 个高频元素*
    • 题目:
    • 思路:
    • 代码:

滑动窗口最大值*

题目链接:链接: 239. 滑动窗口最大值

题目:

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

示例 1:

输入: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

思路:

首先要知道输出数组的长度为len-k+1,然后写出添加元素和删除元素的两个方法,在初始化窗口之后,之后的每一次循环将队头元素存入res数组直至循环结束。
添加元素:每次添加一个元素时,保证每一次循环后队头元素是最大的!(在k>=2,队列中可以出现相同的最大元素)
删除元素:在初始化窗口之后,每一次循环后要保证队列中没有本次窗口之外的元素。(以示例代码)例如:第一次循环后,保证下标为0的元素(1)不在队列中;第二次循环后,保证下标为1的元素(3)不在队列中

代码:

用时32ms,内存57,3MB

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        int[] res = new int[n-k+1];
        Deque<Integer> queue = new ArrayDeque<>();
        
        //窗口初始化
        for(int i = 0; i < k; i++){
            Add(queue,nums[i]);
        }
        int index = 0;
        res[index++] = queue.peek();
        
        //先进行删除操作,后进行添加
        for(int i = k; i < n; i++){
            Delete(queue,nums[i-k]);
            Add(queue,nums[i]);
            res[index++] = queue.peek();
        }
        
        return res;
    }
    
    //添加元素:比队尾元素大就排出队尾元素,然后继续与队尾比较,这样就能保证每一次循环后队头元素是最大的!
    public Deque<Integer> Add(Deque<Integer> queue, int num){
        while(!queue.isEmpty() && num > queue.peekLast()){
            queue.pollLast();
        }
        queue.offer(num);
        return queue;
    }
    
    //删除元素:将本次循环要被删除的元素与队头元素比较,若不相等,则表示在进行添加操作时已经排出了前者,直接进行返回就行;若相等,就要排出队头元素再返回
    public Deque<Integer> Delete(Deque<Integer> queue,int num){
        if(!queue.isEmpty() && num == queue.peek()){
            queue.poll();
        }
        return queue;
    }
}

用时41ms,内存58,3MB

//自定义数组
class MyQueue {
    Deque<Integer> deque = new LinkedList<>();
    void poll(int val) {
        if (!deque.isEmpty() && val == deque.peek()) {
            deque.poll();
        }
    }
    //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出
    //保证队列元素单调递减
    //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2
    void add(int val) {
        while (!deque.isEmpty() && val > deque.getLast()) {
            deque.removeLast();
        }
        deque.add(val);
    }
    //队列队顶元素始终为最大值
    int peek() {
        return deque.peek();
    }
}

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums.length == 1) {
            return nums;
        }
        int len = nums.length - k + 1;
        //存放结果元素的数组
        int[] res = new int[len];
        int num = 0;
        //自定义队列
        MyQueue myQueue = new MyQueue();
        //先将前k的元素放入队列
        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        res[num++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {
            //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列
            myQueue.poll(nums[i - k]);
            //滑动窗口加入最后面的元素
            myQueue.add(nums[i]);
            //记录对应的最大值
            res[num++] = myQueue.peek();
        }
        return res;
    }
}

前 K 个高频元素*

题目链接:链接: 347.前 K 个高频元素

题目:

—给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

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

输入: nums = [1], k = 1
输出: [1]
提示:

  • 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  • 你的算法的时间复杂度必须优于 O ( n log ⁡ n ) O(n \log n) O(nlogn) , n 是数组的大小。
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
  • 你可以按任意顺序返回答案。

思路:

1、统计元素出现频率。【使用map来存储数组中每个元素及其出现的频率】
2、对频率进行排序。【定义一个小顶堆(使用PriorityQueue来实现):从队头到队尾是由小到大排序】
3、找出前k个高频元素。【当添加进优先级队列中的元素(数组)个数大于k时,排出队头元素,剩下的就是频率前k的元素(数组)】

代码:

用时13ms,内存44.3MB

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        //用map获取数组中每个元素及其对应的频率
        Map<Integer,Integer> map = new HashMap<>();
        for(int num : nums)
            map.put(num,map.getOrDefault(num,0) + 1);

        //定义一个堆(lambda 表达式设置优先级队列存储:o1-o2是由小到大,o2-o1是由大到小)
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)->o1[1] - o2[1]);
        for(Map.Entry<Integer,Integer> entry: map.entrySet()){
            //下面的代码是根据小根堆实现的,我只保留优先队列的最后的k个,只要超出了k我就将最小的弹出,剩余的k个就是答案
            pq.offer(new int[]{entry.getKey(),entry.getValue()});
            if(pq.size() > k){
                pq.poll();
            }
        }
        
        //获取结果
        int[] ans = new int[k];
        for(int i = k - 1; i >= 0; i--){
            ans[i] = pq.poll()[0];
        }
        return ans;
        
    }
}

http://www.kler.cn/news/306203.html

相关文章:

  • 初识爬虫2
  • Linux删除SSH生成的密钥对
  • 探索Python的Excel世界:openpyxl的魔法之旅
  • 【homebrew安装】踩坑爬坑教程
  • 路由策略原理与配置
  • C#笔记11 获取线程及其信息,什么是优先级、单元状态、线程状态、执行状态、线程名称以及其他属性?
  • 一文速通calcite结合flink理解SQL从文本变成执行计划详细过程
  • Kubernetes Pod镜像的3种状态
  • STM32-UART配置注释
  • 标准库标头 <bit>(C++20)学习
  • 计算机网络 --- 计算机网络性能【七大性能指标】
  • 如何精确统计Pytorch模型推理时间
  • c语言写的环形队列
  • emWin5的图片半透明之旅
  • 高级java每日一道面试题-2024年9月12日-架构篇[DDD领域驱动篇]-如何使用领域驱动设计(DDD)中的事务脚本模式?
  • Spring4-IoC2-基于注解管理bean
  • comfyui中,sam detector与yoloworld图像分割算法测试以及影响
  • [极客大挑战 2019]PHP
  • 1、常用的数据库、表操作
  • 蒸!--数据在内存中的存储
  • node express 开启多进程
  • python多线程程序设计 之二
  • C#获取计算机信息
  • C++入门基础知识68(高级)——【关于C++ 异常处理】
  • 【系统架构设计师-2010年真题】案例分析-答案及详解
  • Superset二次开发之源码asyncEvent.ts 分析
  • 嵌入式C语言自我修养:C语言的面向对象编程思想
  • 问题 H: 三角数
  • 【在Linux世界中追寻伟大的One Piece】五种IO模型和阻塞IO
  • 13. 神经网络基本骨架--nn.Module