1. 布隆过滤器
一个网站有100亿条url黑名单。随便输入一个url,如何快速判断此url在黑名单中?
- 方法一:使用hash表。若每条url占64Bytes,存储所有url就至少需要640G的内存。(×)
- 方法二:使用位图。开辟一个存储状态的数组,空间消耗依旧很大。(×)
- 方法三:布隆过滤器。
-
本质:位数组
-
初始化:
每个黑名单url经过哈希函数,得到哈希值。(哈希函数为k个)
哈希值%m,描黑位数组。(数组大小为m个bit) -
检查:
一个url通过k个哈希函数,查看在位数组中的位置,若位置全为黑,则认为在布隆过滤器里,否则不在。
-
-
布隆过滤器(位数组)大小
- n:样本量
- p:误判率
- 哈希函数个数
- 预期误判率
参考链接
2. 一致性哈希
-
传统负载均衡
后台数据通过哈希函数,得到哈希值,然后近乎均匀保存在n台服务器中。
前台获得请求,利用哈希函数可以在相应服务器里寻找。缺点:
若增加或减少服务器,则要重新计算相应的哈希值,然后放到相应服务器中。 -
一致性哈希
将哈希值组成一个环,将n台服务器(比如ip值)通过哈希函数,对应到环上。
若文件对应的哈希值在m1与m2之间,则保存在m2机器中;
在m2与m3之间,则保存在m3中。
若此时增加一台服务器,则只需把相应的一段范围里的文件保存在新服务器中。
将保存在m2与m4之间的文件迁移到m4中即可。
- 虚拟节点技术引入
若服务器数n<<哈希值,则极大可能服务器在环上分布不均。
每一台服务器对应m个虚拟节点,这样可以近乎均分环。
3. 并查集
- 判断两元素是否属于同一个集合
- a所在的集合与b所在的集合合并
class UnionFindSet
{
private:
map<Node, Node> fatherMap;
map<Node, int> sizeMap;
public:
UnionFindSet(list<Node> nodes)
{
makeSets(nodes);
}
bool isSameSet(Node a, Node b)
{
return findHead(a) == findHead(b);
}
void Union(Node a, Node b)
{
Node aHead = findHead(a);
Node bHead = findHead(b);
if(aHead != bHead)
{
int aSetSize = sizeMap[aHead];
int bSetSize = sizeMap[bHead];
if(aSetSize <= bSetSize)
{
fatherMap[aHead] = bHead;
sizeMap[bHead] += sizeMap[aHead];
}
else{
fatherMap[bHead] = aHead;
sizeMap[aHead] += sizeMap[bHead];
}
}
}
private:
void makeSets(list<Node> nodes)
{
for(const Node& node : nodes)
{
fatherMap.insert(make_pair(node, node));
sizeMap.insert(make_pair(node, 1));
}
}
Node findHead(Node node)
{
Node father = fatherMap[node];
while(father != node)
{
father = findHead(father);
}
fatherMap[node] = father;
return father;
}
}
一个矩阵中只有0和1两种值,每个位置都可以和自己的上、下、左、右
四个位置相连,如果有一片1连在一起,这个部分叫做一个岛,求一个
矩阵中有多少个岛?
int countIsLands(int **arr, int m, int n)
{
if (arr == nullptr) return 0;
int ret = 0;
for(int i=0; i<m; i++)
for (int j = 0; j < n; j++)
{
if (arr[i][j] == 1)
{
ret++;
infect(arr, m, n, i, j);
}
}
return ret;
}
void infect(int **arr, int m, int n, int i, int j)
{
if (i < 0 || i >= m || j < 0 || j >= n || arr[i][j] != 1)
return;
arr[i][j] = 2; //感染
infect(arr, m, n, i - 1, j);
infect(arr, m, n, i + 1, j);
infect(arr, m, n, i, j - 1);
infect(arr, m, n, i, j + 1);
}
海量元素:
- 例
- 将元素分为两部分,分别统计各块岛数量,并把同一块做标记;
- 处理边界:
若两边同为1,则看它们的标记是否相同,不同,union操作,岛数量-1