代码随想录算法训练营打卡Day13 | LeetCode239 滑动窗口最大值、LeetCode 347前k个高频元素

摘要

  • 如何用双端队列deque实现单调队列,单调队列是指,队列中的元素顺序按非递增、非递减、递增、递减中的一种的队列。
    • 队首根据窗口的滑动出队
    • 队尾根据元素的大小出队
  • 优先级队列priority_queue,大顶堆、小顶堆的使用

今日学习的视频和文章

  • 代码随想录 滑动窗口最大值
  • 代码随想录 前k个高频元素
  • C++Primer 双端队列部分
  • 数据结构C++语言版第二版(清华大学出版社)大顶堆、小顶堆的实现
  • C++函数指针

LeetCode239 滑动窗口最大值

239. 滑动窗口最大值 - 力扣(Leetcode)

  • 初见题目的想法:

    • 这道题目中,滑动窗口中可能的最大值有两种排除可能方式:

      1. 滑动窗口滑过了某个可能的最大值,即该可能最大值不再被包含在当前的滑动窗口内。如以下例子,3不在窗口内。
      1 3 [1 2 0] 5
      
      1. 有一个新的可能最大值进入滑动窗口,其他比这个可能最大值小且有可能在同一个滑动窗口内的值都不可能成为滑动窗口的最大值。可见,在如下的滑动过程中,3和2之间的1,不会有成为滑动窗口最大值的可能。
      1 [3 1 2] 0 5
      1 3 [1 2 0] 5
      
  • 而滑动窗口中的元素先进先出,这让人很自然的联想到队列,所以上述的两个排除可能最大值的方式对应到元素的出队方式就是:

    1. 队首的元素根据窗口的滑动出队,如果队首的元素已经不在当前滑动窗口内,则出队
    2. 队尾的元素根据滑动窗口包含的新的值出队,如果队尾的元素比滑动窗口包含进的新的一个值小,则队尾的元素出队
  • 由于需要从队首和队尾两个方向将元素出队,所以考虑使用双端队列deque

完整的题解代码如下,此处的题解代码的单调队列保存的是元素的下标

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> res;
        deque<int> q;
        for (int i = 0; i < nums.size(); i++) {
            if (!q.empty() &&  i - q.front() == k) {
                q.pop_front();
            }
            while (!q.empty() && nums[i] > nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
            if (i + 1 >= k) {
                res.push_back(nums[q.front()]);
            }
        }
        return res;
    }
};
  • 看了讲解之后的思考:
    • 维护单调队列的关键:尝试新入队的元素不断与队尾元素比较,若队尾元素和尝试新入队的元素不符合我们定义的顺序,则让队尾元素出队。而队首元素的出队是由于滑动窗口的滑动导致包含的元素的变化。

LeetCode 347前k个高频元素

347. 前 K 个高频元素 - 力扣(Leetcode)

  • 解题思路:

    • 先遍历一遍数组nums,使用哈希表unordered_map来记录各元素的出现的频率。
    • 由于题目只要求返回前k个高频元素,所以可以考虑将频数在后n-k个的元素排除。
    • 如果使用大顶堆,当堆中元素个数到达k个时,由于后面还有至少n-k个元素没有进入堆中排序,所以也无法确定堆顶是否是在前k个高频元素中。
    • 如果使用小顶堆,当堆中元素到达k个时,再往堆中加入一个元素并调整为小顶堆后,由于堆顶是当前k+1个元素内频数最小的元素,所以可以确定堆顶元素中不会在前k个高频元素中。将堆顶元素弹出即可(因为已经确定有k个元素的频数大于堆顶元素的频数,自然最后的答案不会有目前的堆顶元素)。
    使用大顶堆 使用小顶堆
    对所有元素按频数进行堆排序,然后从堆顶取k个元素,即为题目要求的k个高频元素 在遍历元素时,保持堆中的元素为k个,遍历完成时,小顶堆中保留的元素即为题目要求的k个元素
    实际上是对所有元素按频数进行排序,然后取前k个高频元素 实际上就是优先队列的思想,频数高的保留在队列中,频数低的优先出队

    完整题解代码如下

    class Solution {
    public:
    
        class minHeapCmp {
        public:
            bool operator()(const pair<int, int>& l, const pair<int, int>& r) {
                return l.second > r.second;
            }
        };
    
        vector<int> topKFrequent(vector<int>& nums, int k) {
            unordered_map<int, int> map;
            for (auto& iter : nums) {
                map[iter]++;
            }
    
            priority_queue<pair<int, int>, vector<pair<int, int>>, minHeapCmp> minHeap;
            for (auto& iter : map) {
                minHeap.push(iter);
                if (minHeap.size() > k) {
                    minHeap.pop();
                }
            }
    
            vector<int> ans(k);
            for (int i = k - 1; i >= 0; i--) {
                ans[i] = minHeap.top().first;
                minHeap.pop();
            }
            return ans;
        }
    };
    
  • 疑惑及要注意的地方:

    • 优先级队列自定义的比较规则,为什么是l.second > r.second,我没有深入的理解,等之后复习完树的内容后,我会尝试用C++实现一个可以自定义比较规则的堆来帮助理解。
    • STL为编程提供了很多便利,但不仅要知道怎么用,更要在使用的过程中思考STL是如何实现的。排斥STL和过度依赖STL都是不利于学习的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339