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

LeetCode 热题 100 堆

215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

提示:

  • 1 <= k <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4

借助快速排序的思想解决topK问题,快速选择将数组划分为三块,对应三种情况进行查找,不断递归即可:

[left, l - 1] [l, r] [r + 1, right]
  • 当k小于等于右区间的长度,既k <= right - r时,继续在右区间查找第k大的数。
  • 当k小于等于右区间+中间相同字符的长度,既k <= right - l + 1时,第k大的数就在中间区间为key
  • 当k大于右区间+中间相同字符的长度时,既k在左区间时,在左区间查找第k大的数减去右区间+中间相同字符的长度,既第k - (right - l + 1)大的数。
int findKthLargest(vector<int>& nums, int k) {srand(time(nullptr));int left = 0, right = nums.size() - 1;return topK(nums, left, right, k);
}int topK(vector<int>& nums, int left, int right, int k) {if (left == right)return nums[left];// 随机获取keyint key = nums[rand() % (right - left + 1) + left];// 数组划分为三块int i = left, l = left, r = right;while (i <= r) {if (nums[i] < key)swap(nums[l++], nums[i++]);else if (nums[i] > key)swap(nums[r--], nums[i]);elsei++;}// [left, l - 1] [l, r] [r + 1, right]if (k <= right - r)return topK(nums, r + 1, right, k);else if (k <= right - l + 1)return key;elsereturn topK(nums, left, l - 1, k - (right - l + 1));
}

快速排序的思想解决topK问题,快速选择将数组划分为三块,对应三种情况进行查找,不断递归即可:

[left, l - 1] [l, r] [r + 1, right]
  • 当k小于等于右区间的长度,既k <= right - r时,继续在右区间查找第k大的数。
  • 当k小于等于右区间+中间相同字符的长度,既k <= right - l + 1时,第k大的数就在中间区间为key
  • 当k大于右区间+中间相同字符的长度时,既k在左区间时,在左区间查找第k大的数减去右区间+中间相同字符的长度,既第k - (right - l + 1)大的数。
int findKthLargest(vector<int>& nums, int k) {srand(time(nullptr));int left = 0, right = nums.size() - 1;return topK(nums, left, right, k);
}int topK(vector<int>& nums, int left, int right, int k) {if (left == right)return nums[left];// 随机获取keyint key = nums[rand() % (right - left + 1) + left];// 数组划分为三块int i = left, l = left, r = right;while (i <= r) {if (nums[i] < key)swap(nums[l++], nums[i++]);else if (nums[i] > key)swap(nums[r--], nums[i]);elsei++;}// [left, l - 1] [l, r] [r + 1, right]if (k <= right - r)return topK(nums, r + 1, right, k);else if (k <= right - l + 1)return key;elsereturn topK(nums, left, l - 1, k - (right - l + 1));
}

347. 前 K 个高频元素

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 105
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

**进阶:**你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

优先级队列 + 哈希

vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int, int> hash;for (int i : nums) {hash[i]++;}auto cmp = [](pair<int, int>& a, pair<int, int>& b) {return a.second > b.second;};// 小根堆priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> que;for (auto& [num, count] : hash) {que.emplace(num, count);if (que.size() > k) {que.pop();}}vector<int> ans;while (!que.empty()) {ans.push_back(que.top().first);que.pop();}return ans;
}

快速排序

void quickSort(vector<pair<int, int>>& v, int left, int right, int k) {if (left >= right) {return;}int key = v[rand() % (right - left + 1) + left].second;int i = left, l = left, r = right;while (i <= r) {if (v[i].second < key) {swap(v[i++], v[l++]);} else if (v[i].second > key) {swap(v[i], v[r--]);} else {i++;}}// [left, l - 1] [l, r] [r + 1, right]if (k <= right - r) {quickSort(v, r + 1, right, k);} else if (k <= right - l + 1) {return;} else {quickSort(v, left, l - 1, k - (right - l + 1));}
}vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int, int> hash;for (int i : nums) {hash[i]++;}vector<pair<int, int>> v;for (auto& p : hash) {v.push_back(p);}srand(time(nullptr));quickSort(v, 0, v.size() - 1, k);vector<int> ans;int i = v.size() -  1;while (k--) {ans.push_back(v[i--].first);}return ans;
}

295. 数据流的中位数

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。
  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

提示:

  • -10^5 <= num <= 10^5
  • 在调用 findMedian 之前,数据结构中至少有一个元素
  • 最多 5 * 10^4 次调用 addNumfindMedian
  • que_min 是大根堆,用于存储数据流中较小的一半元素,堆顶元素是较小的一半元素中最大的元素。
  • que_max 是小根堆,用于存储数据流中较大的一半元素,堆顶元素是较大的一半元素中最小的元素。
priority_queue<int, vector<int>, less<int>> que_min; // 大根堆
priority_queue<int, vector<int>, greater<int>> que_max; // 小根堆MedianFinder() {}void addNum(int num) {if (que_min.empty() || num <= que_min.top()) {que_min.push(num);if (que_min.size() > que_max.size() + 1) {que_max.push(que_min.top());que_min.pop();}} else {que_max.push(num);if (que_max.size() > que_min.size()) {que_min.push(que_max.top());que_max.pop();}}
}double findMedian() {if (que_min.size() > que_max.size())return que_min.top();return (que_min.top() + que_max.top()) / 2.0;
}

http://www.mrgr.cn/news/97401.html

相关文章:

  • 从零搭建微服务项目Pro(第7-1章——分布式雪花算法)
  • 1. Qt信号与槽
  • C语言跳表(Skip List)算法(附链表与跳表实现源码)
  • 从奖励到最优决策:动作价值函数与价值学习
  • Opencv之dilib库:表情识别
  • 人大金仓数据库dum文件进行备份数据和恢复数据
  • 使用OpenSceneGraph生成3D数据格式文件
  • 某碰瓷国赛美赛,号称第三赛事的数模竞赛
  • HarmonyOS 基础组件和基础布局的介绍
  • LeetCode Hot100 刷题笔记(3)—— 链表
  • spring boot 整合redis
  • MySQL窗口函数学习
  • AI爬虫?爬!
  • [ctfshow web入门] 零基础版题解 目录(持续更新中)
  • Nginx-keepalived-高可用
  • Nginx 负载均衡案例配置
  • RAG 架构地基工程-Retrieval 模块的系统设计分享
  • 深度学习环境安装
  • 蓝桥杯嵌入式第十四届模拟二(PWM、USART)
  • K8S学习之基础七十四:部署在线书店bookinfo