「随机算法专题」Count-min Sketch 入门
Point Query 问题:给出个数,,你需要(近似)回答的出现次数。
容易想到直接开一个桶,空间复杂度。我们希望在很大时用更小的空间复杂度解决这个问题。
Count-min Sketch
Count-min Sketch 是一个数据结构,通过随机哈希的方式来给出上述问题的近似解。
考虑构造一个随机哈希函数,将输入的元素均匀映射到个 bucket。
利用这个哈希来计算每个哈希值的出现次数:。那么记的真实出现次数为,显然有,在哈希不冲突时取等。
容易想到,多次采用不同的随机哈希分别统计出现次数,那么取可以很好地逼近。
对此进行更细致的期望分析:
假设哈希函数是均匀随机,那么,于是
于是我们对该随机算法进行误差估计:
这里面用到了 Markov Inequality:若,有。
取可以控制上述概率不大于,那么我们取个独立随机哈希(若已知的上界),即可求出绝对误差在内的近似解。
空间复杂度。
K-Heavy Hitter
K-Heavy Hitter 问题:给出个数,,你需要(近似)求出出现次数前多的所有数。
对于上述问题我们仍然有空间复杂度的朴素算法。
近似 K-Heavy Hitter:要求必须求出所有出现次数不少于的数,并且求出的所有数的出现次数不少于。
若已知,那么求近似解可以直接使用 Count-min Sketch 解决。考虑上界未知但上界已知的情况。
我们维护当前插入的总元素个数。在 Count-min Sketch 的基础上我们额外维护一个集合,用于记录 Count-min Sketch 意义下出现次数不小于的数。每次插入元素后,我们将出现次数小于的数从中删除。
可以发现近似 K-Heavy Hitter 的误差主要是留给 Count-min Sketch。而上述集合的维护其实是足够准确的。
由于出现次数不小于的数字个数是的,因此的空间大小有保证。在考虑到 Count-min Sketch 的误差后可以得出该算法的空间复杂度为。
一个可能的代码实现:
class Solver {
public:
#define FOR(a, b, c) for(int a = (int)(b); a <= (int)(c); a++)
int n1 = 0, k = 0; // current total numbers
int* L, len = 0;
static const int T = 6; // number of hash tables
// const double eps = 0.01;
static const int M = (5 * (1 << 20)) / T; // 2 / eps + 11; // size of hash table
struct hash_table {
int seed;
int* bucket;
hash_table() {}
hash_table(int seed, int* bucket): seed(seed), bucket(bucket) {
FOR(i, 0, M - 1) bucket[i] = 0;
}
void add(int val) {
bucket[fasthash64(val, seed) % M]++;
}
int get(int val) {
return bucket[fasthash64(val, seed) % M];
}
};
hash_table h[T];
int count_min(int e) {
int res = h[0].get(e);
FOR(i, 1, T - 1) res = min(res, h[i].get(e));
return res;
}
// arr 是题目提供的内存空间,约为 32MB
void init(int* arr, int m, int _k) {
k = _k;
FOR(i, 0, T - 1) {
h[i] = hash_table(1145140 + i, arr + M * i);
}
L = arr + M * T;
}
void add(int e) {
++n1;
FOR(i, 0, T - 1) h[i].add(e);
FOR(i, 0, len - 1) {
if (count_min(L[i]) < n1 * 1.0 / k) { // delete it
L[i] = L[len - 1];
--len, --i;
}
}
if (count_min(e) >= n1 * 1.0 / k) {
FOR(i, 0, len - 1) {
if (L[i] == e) return;
}
L[len++] = e;
}
}
std::vector<int> report() {
return vector<int>(L, L + len);
}
};
修订记录
- 2023年3月9日 创建文章