首页 > 编程语言 >代码随想录算法训练营第十三天|单调数列:滑动窗口最大值(力扣239.)、优先级队列:前k个高频元素(力扣347.)

代码随想录算法训练营第十三天|单调数列:滑动窗口最大值(力扣239.)、优先级队列:前k个高频元素(力扣347.)

时间:2023-08-15 23:13:42浏览次数:41  
标签:nums int 元素 随想录 力扣 队列 push 小顶 第十三天

单调数列:滑动窗口最大值(力扣239.)

  • 给定滑动窗口的范围,求每个滑动窗口范围内的最大值
  • 使用单调队列实现
  • 对于最大值数字前面的数字不存入数列,对于最大值数字后面的数字存入数列中
  • 单调队列中数字的大小呈递减顺序
  • pop(value):如果窗口移除的元素等于单调队列的队口元素,则pop;否则什么也不干
  • push(value):如果入口元素小于push的元素value,则一直弹出队尾元素,直到队尾元素大于等于push元素
  • pop从队头走,push从对尾进
  • 核心思想:只保留窗口内的有效元素,即较大值的排序较小的元素全部不进队列,并在每次push元素时保持队列的队头是此时最大值。
  • 双端队列的api:获取队尾值:getLast();弹出队尾值removeLast();弹出队头值poll();
  • 获取队头值且不弹出:peek();
class MyQueue{
    Deque<Integer> deque = new LinkedList<>();
    //弹出元素时,要考虑要弹出的元素是否为队头元素,如果是,则弹出;如果不是,则什么也不干
    void poll(int val){
        if(!deque.isEmpty()&&deque.peek()==val){
            deque.poll();
        }
    }
    //推入元素时,要考虑push的元素值是否都小于队尾元素,如果是,则直接push;如果不是,一直输出队尾元素
    void push(int val){
        while(!deque.isEmpty()&&deque.getLast() < val){
            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.push(nums[i]);
        }
        res[num++] = myQueue.peek();
        //将之后的元素放入
        for(int j = k; j < nums.length;j++){
            myQueue.poll(nums[j-k]);
            myQueue.push(nums[j]);
            res[num++] = myQueue.peek();
        }
        return res;
    }
}

(仅理解思路)优先级队列:前k个高频元素(力扣347.)

  • 题目:给定一个非空的整数数组,返回其中出现频率前k高的元素
  • 涉及三块内容:1.统计元素出现频率 2. 对频率排序 3. 找出前k个高频元素
  • 大顶堆和小顶堆:
  • 堆的底层就是一个二叉树:大顶堆就是父树比它所有子树的值要大
  • 优先级队列的底层实现方式就是堆
  • 我们要用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        //基于小顶堆实现
        Map<Integer,Integer> map = new HashMap<>();
        for(int num:nums){
            map.put(num,map.getOrDefault(num,0)+1);
        }
        //用小顶堆实现
        //优先队列PriorityQueue
        PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
         for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序
            if(pq.size()<k){//小顶堆元素个数小于k个时直接加
                pq.add(new int[]{entry.getKey(),entry.getValue()});
            }else{
                if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)
                    pq.poll();//弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了
                    pq.add(new int[]{entry.getKey(),entry.getValue()});
                }
            }
        }
        int[] ans = new int[k];
        for(int i=k-1;i>=0;i--){//依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多
            ans[i] = pq.poll()[0];
        }
        return ans;
    }
}

标签:nums,int,元素,随想录,力扣,队列,push,小顶,第十三天
From: https://www.cnblogs.com/zcctxr/p/17632679.html

相关文章

  • 力扣---833. 字符串中的查找与替换
    你会得到一个字符串 s (索引从0开始),你必须对它执行 k 个替换操作。替换操作以三个长度均为 k 的并行数组给出:indices, sources,  targets。要完成第 i 个替换操作:检查 子字符串  sources[i] 是否出现在 原字符串 s 的索引 indices[i] 处。如果没有出......
  • [代码随想录]Day18-二叉树part07
    题目:530.二叉搜索树的最小绝对差思路:一个关键问题——BST的中序遍历是由小到大的顺序,也就是说记录遍历的前一个节点,每次比较当前节点-前一个节点的值即可(因为由小到大所以当前>前一个)代码:/***Definitionforabinarytreenode.*typeTreeNodestruct{*Val......
  • 代码随想录算法训练营第十一天|力扣20.有效的括号、力扣1047.删除字符串中所有相邻重
    有效的括号(力扣20.)括号匹配时使用栈解决的经典问题题意其实就像我们在写代码的过程中,要求括号的顺序是一样的有左括号,那么在对应位置则必须有右括号第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以returnfalse第二种情况:遍历字......
  • 力扣- 删除有序数组中的重复项
    给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:更改......
  • [代码随想录]Day17-二叉树part06
    题目:654.最大二叉树思路:和前中序构造树差不多的方法,以前是返回值,现在是返回树代码:/***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint*Left*TreeNode*Right*TreeNode*}*/funcconstructMaximumBinaryTree(nums[]in......
  • [代码随想录]Day16-二叉树part05
    题目:513.找树左下角的值思路:层序遍历是最好的选择了,先放右节点,再放左节点最后一个元素就是最左侧的节点。说白了层序遍历就是广度优先搜索BFS。代码:funcfindBottomLeftValue(root*TreeNode)int{node:=rootq:=[]*TreeNode{root}forlen(q)>0{......
  • 力扣---23. 合并 K 个升序链表
    给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。 示例1:输入:lists=[[1,4,5],[1,3,4],[2,6]]输出:[1,1,2,3,4,4,5,6]解释:链表数组如下:[1->4->5,1->3->4,2->6]将它们合并到一个有序链表中得到。1->1->2->3->......
  • [代码随想录]Day15-二叉树part04
    题目:110.平衡二叉树思路:就是后序,如果左右差的超过了1,那么就直接返回-1,如果最后收到了-1那一定是false。代码:/***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint*Left*TreeNode*Right*TreeNode*}*/funcisBalanced(......
  • 代码随想录算法训练营第十六天| 104.二叉树的最大深度 111.二叉树的最小深度 222.
      104.二叉树的最大深度 (优先掌握递归)    卡哥建议:什么是深度,什么是高度,如何求深度,如何求高度,这里有关系到二叉树的遍历方式。大家要先看视频讲解,就知道以上我说的内容了,很多录友刷过这道题,但理解的还不够。   题目链接/文章讲解/视频讲解:https://programmerc......
  • 代码随想录算法训练营第十五天| 层序遍历 10 ,226.翻转二叉树 101.对称二叉树 2
     层序遍历   卡哥建议:看完本篇可以一口气刷十道题,试一试, 层序遍历并不难,大家可以很快刷了十道题。  题目链接/文章讲解/视频讲解:https://programmercarl.com/0102.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86.html  做题思......