讲解视频:https://www.bilibili.com/video/BV12i4y1f7ky/

堆的本质

堆是一种特殊的完全二叉树。每一个节点的值都大于等于或者小于等于其孩子节点的值。

堆的操作时间复杂度如下:

  • 插入:O(logn)O(log_n)O(logn​)
  • 删除:O(logn)O(log_n)O(logn​)
  • 获取最大/最小值:O(1)O(1)O(1)

堆的分类(大根堆、小根堆)

大根堆

数据结构(STL优先队列实现)表示:priority_queue<int> q;

小根堆

表示方法:priority_queue<int, vector<int>, greater<int> q;

图片选自“爱学习的饲养员”小姐姐手绘

实战

一般用于TOP K类型。

前K个最大值就小根堆;前K个最小值就大根堆(贪心)

先把STL的优先队列写前面

priority_queue<Type, Container, Functional> //数据类型 容器类型 比较方式

大根堆模板如下:(Top K最小值)

priority_queue<int> q; //定义大根堆
for(auto &i : arr) //arr是容器 这里假设是vector<int> arrif(q.size() < k) q.push(i);else if(i < q.top())  //贪心策略q.pop(), q.push(i);

小根堆模板如下:(Top K最大值)

priority_queue<int, vector<int>, greater<int>> q; //定义小根堆
for(auto &i : nums)//假设 vector<int> numsif(q.size() < k) q.push(i);else if(q.top() < i) q.pop(), q.push(i);

intpair<int, int>后的模板如下:

在写模板之前要了解对pair的排序默认为对第一个值(.first)排序,如果想要对第二个值排序需要由自定义函数实现。

static bool cmp1(pair<int, int> &p1, pair<int, int> &p2)
{return p1.y > p2.y; //是否交换 父节点将小于子节点 所以小根堆
}
static bool cmp2(pair<int, int> &p1, pair<int, int> &p2)
{return p1.y < p2.y; //是否交换 父节点将大于子节点 所以大根堆
}priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp1)> q(cmp1); //自定义排序second 小根堆priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; //默认对first排序 小根堆priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp2)> q(cmp2); //自定义排序second 大根堆

直接上四个裸题吧,把上面的模板一套就AC了,具体怎么套不再赘述:(点击文字跳转题目)

一、剑指 Offer 40. 最小的k个数

二、数组中的第K个最大元素

三、数据流中的第 K 大元素

四、前 K 个高频元素(pair<int, int> 自定义排序)

p.s.依据“爱学习的饲养员”小姐姐讲解、对她的讲解做的笔记

(快去关注“爱学习的饲养员”小姐姐吧~


修改时间:2022.2.17

更新背景:昨天躺床上睡觉(实际在玩犯罪大师。更新了互动板块,贼好玩。玩到了两点半)时想到不能只有简单的模板题、那样会让满怀期待的人失望。又想到我还没补周赛题(老咕咕了)、只是十五那天中午去北湖的时候看着湖面想了想。于是这道题被加了进来。

压轴题、删除元素后和的最小差值

题目

给你一个下标从 0 开始的整数数组 nums ,它包含 3 * n 个元素。

你可以从 nums 中删除 恰好 n 个元素,剩下的 2 * n 个元素将会被分成两个 相同大小 的部分。

前面 n 个元素属于第一部分,它们的和记为 sumfirst 。
后面 n 个元素属于第二部分,它们的和记为 sumsecond 。

两部分和的 差值 记为 sumfirst−sumsecondsum_{first} - sum_{second}sumfirst​−sumsecond​ 。

比方说,sumfirst = 3 且 sumsecond = 2 ,它们的差值为 1 。
再比方,sumfirst = 2 且 sumsecond = 3 ,它们的差值为 -1 。

请你返回删除 n 个元素之后,剩下两部分和的 差值的最小值 是多少。

示例 1:输入:nums = [3,1,2]
输出:-1
解释:nums 有 3 个元素,所以 n = 1 。
所以我们需要从 nums 中删除 1 个元素,并将剩下的元素分成两部分。- 如果我们删除 nums[0] = 3 ,数组变为 [1,2] 。两部分和的差值为 1 - 2 = -1 。
- 如果我们删除 nums[1] = 1 ,数组变为 [3,2] 。两部分和的差值为 3 - 2 = 1 。
- 如果我们删除 nums[2] = 2 ,数组变为 [3,1] 。两部分和的差值为 3 - 1 = 2 。两部分和的最小差值为 min(-1,1,2) = -1 。示例 2:输入:nums = [7,9,5,8,1,3]
输出:1
解释:n = 2 。所以我们需要删除 2 个元素,并将剩下元素分为 2 部分。
如果我们删除元素 nums[2] = 5 和 nums[3] = 8 ,剩下元素为 [7,9,1,3] 。和的差值为 (7+9) - (1+3) = 12 。
为了得到最小差值,我们应该删除 nums[1] = 9 和 nums[4] = 1 ,剩下的元素为 [7,5,8,3] 。和的差值为 (7+5) - (8+3) = 1 。
观察可知,最优答案为 1 。

提示:

nums.length == 3 * n
1 <= n <= 105
1 <= nums[i] <= 105

分析

  • 题目自定义了差值 -> 两部分和的 差值 记为 sumfirst−sumsecondsum_{first} - sum_{second}sumfirst​−sumsecond​ 。
  • 用堆求出前面和后面的前缀和
  • 枚举分割点

参考代码

typedef long long LL;
class Solution {public:long long minimumDifference(vector<int>& nums) {//令前缀和左闭右开int n = nums.size(), m = n / 3;priority_queue<int> q1;priority_queue<int, vector<int>, greater<int>> q2;//a从左到右 b从右到左(前缀和)vector<LL>a(n + 1), b(n + 1);//用堆计算Top KLL tmp = 0;for(int i = 0; i < m; ++ i) {tmp += nums[i];q1.push(nums[i]);} a[m] = tmp;for(int i = m; i < m * 2; ++ i){if(nums[i] < q1.top()){tmp = tmp - q1.top() + nums[i];q1.pop();q1.push(nums[i]);}a[i + 1] = tmp; }tmp = 0;for(int i = n - 1; i >= 2 * m; -- i){tmp += nums[i];q2.push(nums[i]);}b[m] = tmp;int idx = m;for(int i = 2 * m - 1; i >= m; -- i){if(nums[i] > q2.top()){tmp = tmp - q2.top() + nums[i];q2.pop();q2.push(nums[i]);}b[ ++ idx] = tmp;}//枚举分割点LL minn = 1e11;for(int i = m; i <= m * 2; ++ i)minn = min(minn, a[i] - b[n - i]);return minn;}
};

STL优先队列实现堆(模板 附力扣题目)相关推荐

  1. 力扣题目——429. N 叉树的层序遍历

    注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路. 描述 给定一个 N 叉树,返回其节点值的层序遍历.(即从左到右,逐层遍历). 树的 ...

  2. 力扣题目——637. 二叉树的层平均值

    注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路. 描述 给定一个非空二叉树, 返回一个由每层节点平均值组成的数组. 示例: 输入: ...

  3. 力扣题目——103. 二叉树的锯齿形层序遍历

    注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路. 描述 给定一个二叉树,返回其节点值的锯齿形层序遍历.(即先从左往右,再从右往左进行 ...

  4. 力扣题目——107. 二叉树的层序遍历 II

    注:本文的代码实现使用的是 JS(JavaScript),为前端中想使用JS练习算法和数据结构的小伙伴提供解题思路. 描述 给定一个二叉树,返回其节点值自底向上的层序遍历. (即按从叶子节点所在层到根 ...

  5. 算法面试不懂这6大数据结构知识一定挂!(附力扣LeetCode真题讲解)

    本文作者:苏勇,Google 资深技术工程师 首发地址:https://mp.weixin.qq.com/s/u8pvmupISQ5D4kGIkgfKbA 在互联网行业的算法面试中经常会被考到数据结构 ...

  6. 基本算法总结,力扣题目整理

    系统性学习算法,扎实您的打码基本功! 作为算法初学者的我从19年8月份开始在力扣学习算法,到现在AC了700多道题目. 随着打卡题目数量的增多,我发现算法常见考察的知识点大概有十几种,包括:二分,滑动 ...

  7. 力扣题目归类,顺序刷题不再难

    目录 介绍 前奏-基础篇 中篇-链表.树的相关操作 进阶-回溯.动态规划 脑筋急转弯 介绍 大家好,相信很多人都知道刷力扣的重要性,但是如果不能将题目很好的归类整理专一练习,而是东做一道西做一道,那么 ...

  8. 零尽其用,尾随不落——探究力扣题目“移除字符串中的尾随零”的解题思路

    本篇博客会讲解力扣"2710. 移除字符串中的尾随零"的解题思路,这是题目链接. 先来审题: 以下是示例: 以下是提示: 本题的思路是: 先遍历字符串,找到字符串末尾的\0. 从\ ...

  9. C++STL优先队列小根堆大根堆自定义的应用

    小根堆 greater #include<iostream> #include<queue> using namespace std; priority_queue<in ...

最新文章

  1. 好文转载——追求卓越之旅
  2. |NOIOJ|动态规划|3532:最大上升子序列和
  3. ubuntu-11.10-server-i386学习笔记-SVN版本服务器安装
  4. android 通讯录 备份,安卓Android手机通讯录怎么备份 卓联系人备份 卓手机联系人导出...
  5. python获取他人的ip_Python获取指定网段正在使用的IP
  6. TensorFlow神经网络(一)前向传播
  7. 在浏览器中执行Kettle job或者transformation
  8. Visual C++中的异常处理浅析[轉]
  9. Cannot find class ‘org.apache.hudi.hadoop.HoodieParquetInputFormat‘
  10. C语言 扫雷游戏(代码+注释)
  11. Python的视频分析
  12. Win7系统能用一键装机的方式安装win10吗?
  13. DEVELOPMENT OF A LOW-COST VISION SYSTEM FOR FINDING CONTOUR AND SURFACE DEFECTS ON CAST IRON ENGINE
  14. PHP连接MYSQL没有反应
  15. MATLAB中的小技巧
  16. 使用mysql数据库_wuli大世界_新浪博客
  17. 连接数据库的Provider、Driver等字符串的写法
  18. Linux安装yum(红帽子)rpm
  19. xinetd 服务
  20. python猜单词游戏实验原理_猜单词游戏课程设计报告

热门文章

  1. 51Nod 1256-乘法逆元(扩展欧几里德)
  2. HDU 2452 Navy maneuvers (记忆化搜索)
  3. 【愚公系列】2022年09月 微信小程序-WebGL画渐变色正方形
  4. 拒绝毒瘤:推特正试图让“回复人”闭嘴
  5. MPEG音频编码及分析
  6. 法国DREAM方案SAM5504B/SAM5704B音源芯片
  7. 面试题1 -- Java 中,怎么在格式化的日期中显示时区?
  8. 昆山杜克大学计算机专业,昆山杜克大学有哪些专业 附特色重点专业名单
  9. 读者写者模型---读优先与写优先
  10. 得不偿失!博士骗领210万元、硕士骗领3万元人才补贴,全被判刑了!