TOP-K Problems
最小的K个数
- 直接数组排序,取出前K个。复杂度\(O(nlogn)\)。
- 分治
此题只要求出最小的K个数,并不要求这K个数有序。
我们可以借鉴快排中的partition做法,将比第K个数小的都放前面,其余都放后面,即得到答案,但是这种方法会改变原有数组:
class Solution {
public:
vector<int> topKMin(vector<int>& nums, int k) {
if (k < 1 || k > nums.size()) {
return {};
}
int start = 0, end = nums.size() - 1;
int index = partition(nums, start, end);
while (index != k - 1) {
if (index > k - 1) {
end = index - 1;
index = partition(nums, start, end);
}
else {
start = index + 1;
index = partition(nums, start, end);
}
}
return vector<int>(begin(nums), begin(nums) + k);
}
private:
int partition(vector<int>& nums, int l, int r) {
if(nums.empty() || l < 0 || r >= nums.size())
return -1;
int pivotIndex = randomNum(l, r);
swap(nums[pivotIndex], nums[r]);
int smaller = l - 1;
for (int i = l; i < r; ++i) {
if (nums[i] <= nums[r]) {
++smaller;
swap(nums[smaller], nums[i]);
}
}
++smaller;
swap(nums[smaller], nums[r]);
return smaller;
}
int randomNum(int x, int y) {
srand(time(0)); // use system time as seed
return x + rand() % (y - x + 1);
}
};
可以得到递归关系:\(T(n)=T(n/2)+n\),由主定理可知复杂度\(O(n)\)。
与快排不同的是:快排要处理2个子问题,故为\(T(n)=2T(n/2)+n\),复杂度\(O(nlogn)\)。
关于复杂度,还可以用代入法证明:
\]
重复k次后:
\]
故:\(T(n)=n+n/2+n/4+...+1=2n+1\)
- 堆/红黑树
主要思路是用容器存储K个数,之后不断更新:如果当前值小于容器最大值,替换最大值。
用最大堆作为容器,删除及插入\(O(lgk)\),故总复杂度\(O(nlgk)\):
// max heap
class Solution {
public:
priority_queue<int> topKMin(vector<int>& nums, int k) {
if (k < 1 || k > nums.size()) {
return {};
}
priority_queue<int> q;
for (vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
if (q.size() < k) {
q.push(*it);
}
else {
if (q.top() > * it) {
q.pop();
q.push(*it);
}
}
}
return q;
}
};
当然也可以使用红黑树:
// multiset
class Solution {
public:
vector<int> topKMin(vector<int>& nums, int k) {
if (k < 1 || k > nums.size()) {
return {};
}
multiset<int, greater<int>> ms;
for (vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
if (ms.size() < k) {
ms.insert(*it);
}
else {
if (*ms.begin() > * it) {
ms.erase(ms.begin());
ms.insert(*it);
}
}
}
return vector<int>(ms.begin(), ms.end());
}
};
之所以说这种解法适用于海量数据,是因为很多时候不能一次性把数据读入内存处理,这种解法可以从硬盘一次读一个,判断是否放入容器即可,只需要在内存中存储容器即可。
最常出现的K个数
- 统计出现频率,排序后取出前K个。复杂度\(O(nlgn)\)。
- 最小堆。维护K个数,如果新数的频率大于堆顶,替换之。复杂度\(O(nlgk)\)。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> ans;
unordered_map<int, int> cnt;
for (int i = 0; i < nums.size(); ++i) {
++cnt[nums[i]];
}
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
for (auto p : cnt) {
q.emplace(p.second, p.first);
if (q.size() > k) {
q.pop();
}
}
for (int i = 0; i < k;++i) {
ans.push_back(q.top().second);
q.pop();
}
return ans;
}
};
- 桶排。用很多桶记录不同频率到对应数字的映射。时间\(O(n)\),空间\(O(n)\)。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> ans;
unordered_map<int, int> cnt;
int maxFre = 0;
for(const int i : nums) {
maxFre = max(maxFre, ++cnt[i]);
}
unordered_map<int, vector<int>> bucket; // freq -> nums
for(const auto& p : cnt) {
bucket[p.second].push_back(p.first);
}
for(int i = maxFre;i > 0;--i) {
for(int a : bucket[i]) {
ans.push_back(a);
if(ans.size() == k) {
return ans;
}
}
}
return ans;
}
};
TOP-K Problems的更多相关文章
- [LeetCode] Top K Frequent Elements 前K个高频元素
Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...
- C#版(打败99.28%的提交) - Leetcode 347. Top K Frequent Elements - 题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...
- [LeetCode] 347. Top K Frequent Elements 前K个高频元素
Given a non-empty array of integers, return the k most frequent elements. Example 1: Input: nums = [ ...
- 【leetcode】347. Top K Frequent Elements
题目地址:https://leetcode.com/problems/top-k-frequent-elements/ 从一个数组中求解出现次数最多的k个元素,本质是top k问题,用堆排序解决. 关 ...
- 【LeetCode】692. Top K Frequent Words 解题报告(Python)
[LeetCode]692. Top K Frequent Words 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/top ...
- Leetcode 347. Top K Frequent Elements
Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...
- 大数据热点问题TOP K
1单节点上的topK (1)批量数据 数据结构:HashMap, PriorityQueue 步骤:(1)数据预处理:遍历整个数据集,hash表记录词频 (2)构建最小堆:最小堆只存k个数据. 时间复 ...
- LeetCode "Top K Frequent Elements"
A typical solution is heap based - "top K". Complexity is O(nlgk). typedef pair<int, un ...
- [IR] Ranking - top k
PageRanking 通过: Input degree of link "Flow" model - 流量判断喜好度 传统的方式又是什么呢? Every term在某个doc中的 ...
- 347. Top K Frequent Elements
Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...
随机推荐
- C++静态库和动态库
静态库与动态库 首先简单介绍一下gcc 指令 ubuntu 下安装gcc g++ 方法 sudo apt install gcc g++ gcc 的简单使用 建立hello.c 源文件 gcc hel ...
- 《深入理解 Java 虚拟机》读书笔记:垃圾收集器与内存分配策略
正文 垃圾收集器关注的是 Java 堆和方法区,因为这部分内存的分配和回收是动态的.只有在程序处于运行期间时才能知道会创建哪些对象,也才能知道需要多少内存. 虚拟机栈和本地方法栈则不需要过多考虑回收的 ...
- 天天在用Redis,持久化方案你又知道哪些?
前言 文章首发于微信公众号[码猿技术专栏]:天天用Redis,持久化方案有哪些你知道吗? Redis目前已经成为主流的内存数据库了,但是大部分人仅仅是停留在会用的阶段,你真的了解Redis内部的工作原 ...
- 安装python3.8和python2.7
在同一台电脑上同时安装Python2和Python3 目前Python的两个版本Python2和Python3同时存在,且这两个版本同时在更新与维护. 到底是选择Python2还是选择Python3, ...
- stand up meeting 11/25/2015 暨sprint2总结
今天在课堂上进行了小组项目的阶段性总结,这两天小组内也是频繁的开会,具体细节我们已经反复核查,具体不表~ sprint2个人工作总结: 冯晓云:完成了必应词典在线查词api的调用和网络状况的检测:完成 ...
- 实验一 熟悉IDLE和在线编程平台
实验目的 1.掌握python IDLE集成开发环境的安装与使用 2.熟悉在线编程平台 3.掌握基本的python程序编写.编译与运行程序的方法 实验内容 1.按照实验指导安装IDLE,尝试交互式运行 ...
- 你自学半年也搞不懂的go底层,看这篇。这篇讲 go的数组、切片、Maps
目录 数组 1.定义数组 2.使用数组 3.定义并赋值 4.数组的大小是类型的一部分 5.数组是值类型(当参数传递到函数中,修改不会改变原来的值) 6.数组长度 7.循环数组 8.多维数组 切片 1. ...
- 多窗体及窗体之间传值 以及listview的使用
三中打开窗口窗体状态: 1 messagebox.show 类型 特点: 从窗口form 1里打开另一个窗体form2,form2不关闭的情况下form1 不能操作:代码如下: private ...
- pyinstaller打包
参考 官网:http://www.pyinstaller.org/ pyinstaller参数使用 使用spec文件 安装 Windows依赖pypiwin32,新版的pyinstaller已经包含了 ...
- 2019 kali安装pip/pip3
新版的kali中内置的python没有安装pip 0x01 pip(python2)安装: https://bootstrap.pypa.io/2.6/get-pip.py python2 get-p ...