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 ...
 
随机推荐
- selenium.webdriver元素定位失败
			
错误提示: Traceback (most recent call last): File "E:/PythonData/Login/venv/logIn.py", line 18 ...
 - layui经典模块化前端UI框架初识
			
layui产生背景 layui相对于vue来说确实稍有逊色,但是官网提供的入门文档以及完善的框架结构,使的很多人开始用layui来开发前端页面,那么什么人会去使用layui呢? 针对后端开发人员,在对 ...
 - 这个案例写出来,还怕跟面试官扯不明白 OAuth2 登录流程?
			
昨天和小伙伴们介绍了 OAuth2 的基本概念,在讲解 Spring Cloud Security OAuth2 之前,我还是先来通过实际代码来和小伙伴们把 OAuth2 中的各个授权模式走一遍,今天 ...
 - How to generate entities from database schema using doctrine-orm-module
			
1.安装好doctrine,在composer.json中添加如下 "require": { "php": "^5.6 || ^7.0", ...
 - linux之进程管理(二)
			
一.查看进程 ps aux 查看系统所有的进程数据 ps -lA 查看所有系统的数据 ps axjf 连同部分进程树状态 ps参数 -A 显示所有进程,等效 -e -a 不与ter ...
 - linux中的隐藏权限,chattr,lsattr
			
chattr chattr可以用来制约root的权限,使得系统更加安全. 主要参数: a:让文件或目录仅供附加用途. b:不更新文件或目录的最后存取时间. c:将文件或目录压缩后存放. d:将文件或目 ...
 - 22.4 Extends --super 和 this 的区别
			
/* * this和super的区别 this:当前对象的引用 调用子类的成员变量 调用子类的成员方法 在子类的构造方法第一行调用子类其他构造方法 super:子类对象的父类引用 调用父类的成员变量 ...
 - 安卓广播api介绍,给自己理清楚概念
			
广播接收器类概述 这是用于接收由sendBroadcast()发送intent的基类.这个类一般都会被继承重写里面的onReceive()方法..如果您不需要跨应用程序发送广播,请考虑使用LocalB ...
 - 收集免费的接口服务,做一个api的搬运工
			
hello, 大家好,今天给大家推荐的开源项目在某种程度上极大的方便了广大的开发者,这个开源项目统计了网上诸多的免费API,为广大开发者收集免费的接口服务,专心致志做一个API的搬运工,每月定时更新新 ...
 - Map使用foreach遍历方式,Map获取第一个键值
			
List<Map<String, Object>> mapList = new ArrayList<>(); for (Map.Entry<String,O ...