【声明】 图源:牛客网
基本概念
- 算术运算的常见操作符:
+、-、*、/、% - 位运算的常见操作符:
&(按位与)、|(按位或)、^(按位异或)、~(取反)、<<(左移右侧补零)、>>(右移左侧补符号位)、>>>(右移左侧补零)
经典案例
案例一
题目
布隆过滤器
不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL最多占用64个字节。现在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单。请设计系统,要求该系统允许有万分之一以下的判断失误率,并且使用额外空间不要超过30G。
分析
考察点:大数据、位运算
- 应用场景
- 容忍一定程度的失误率,对空间要求较严格==>布隆过滤器
- 网页黑名单系统
- 垃圾邮件过滤系统
- 爬虫的网址判断重复系统
- 容忍一定程度的失误率,对空间要求较严格==>布隆过滤器
- 普通方法
- 将黑名单存入哈希表或数据库,接下来就是对每个URL进行查询,判断其是否在黑名单里
- 此时:数据量100亿、单个URL占64字节,则需要空间$64Byte*100亿=6400亿Byte=640G$空间
- 此方法违反了额外空间的限制
布隆过滤器
可精确地代表一个集合
可精确地判断某一元素是否在此集合中
精确度由用户的具体设计决定,做到100%的精确是不可能的
优势:利用很少的空间,可以做到精确率较高
针对本题,布隆过滤器的具体实现思路如下:
- 定义
bitarray,每个位置一个bit,分0(白)1(黑)两种状态 - 假设共有K个哈希函数,输出域>=m,优秀且各自独立
- 对同一个URL,经过K个哈希函数计算出来的结果也是相互独立的
- 每个计算出来的结果对m取余,在
bitarray上对应的位置处记录为1(描黑) - 接下来对所有的URL进行上述3~4操作,生成一个完整的布隆过滤器
- 定义
如何检测某个URL是否在上述生成的布隆过滤器中?
- 假设待测URL=a,对a进行K个哈希函数计算,结果对m取余,得到0~m-1范围上的K个值
- 接下来在
bitarray上比较这K个值是否都是黑的,如果有一个不为黑,则a一定不在集合里;如果都为黑,说明a在此集合里(但是也有可能产生误判) - 产生误判的原因:
- 如果在生成布隆过滤器的过程中,因为输入的对象过多而
bitarray的空间又过小时,会导致bitarray上绝大多数位置都已经变黑了,在检测a时,由于K个位置上已经描黑,会错误地判断a在集合中。(宁可错杀三千,不可放过一个)
- 如果在生成布隆过滤器的过程中,因为输入的对象过多而

布隆过滤器的
bitarray大小如何确定?- 大小为m,样本数量为n,失误率为p,m有n和p来决定
- 分析本题场景:n=100亿,p=0.01%,单个样本大小不影响布隆过滤器大小,只影响了哈希函数的实现细节
- $m=-\frac{n×lnp}{(ln2)^2}$,求得m=19.19n,向上取整为20n,2000亿bit约为25G
- $k=ln2×\frac{m}{n}=0.7×\frac{m}{n}$,求得k=14(需要14个彼此独立的哈希函数)
- 只要让每个哈希函数都能接收64bytes的字符串类型参数,并且返回的哈希值范围大于0~2000亿
- 失误率计算公式$(1-e^{-\frac{nk}{m}})^k$,求得真实失误率p=0.006% < 0.01%
- 哈希函数本身不占什么空间,所以使用的空间就是bitarray的大小即25G的空间
总结生成布隆过滤器的过程:
- 注意到题目允许有一定程度的失误率
- 根据样本个数n,和允许的失误率p,结合以下公式$m=-\frac{n×lnp}{(ln2)^2}$求出m
- 根据已经求得的m,以及以下公式$k=ln2×\frac{m}{n}=0.7×\frac{m}{n}$求得哈希函数个数k
案例二
题目
如何不用任何额外变量交换两个整数的值?
分析
实现
// 解法一 |
案例三
题目
给定两个32位整数a和b,返回a和b中较大的。但是不能用任何比较判断
分析
- 方法一
sign():取得32位整数符号,如果不是负数返回1,如果是负数返回0。
getMax1():scA和scB只会有一个为1,另一个为0。如果a-b不是负数,scA为1,scB为0;如果a-b是负数,scA为0,scB为1。
- 方法二
实现
public class Compare { |
案例四
题目
给定一个整型数组arr,其中只有一个数出现了奇数次,其他的数都出现了偶数次,请打印这个数。要求时间复杂度为O(N),空间复杂度为O(1)
分析
- n与0异或结果为n,n与n异或结果为0
- eo=0,arr=[C,B,D,A,A,B,C],在遍历数组的过程中将每个数都与eo异或,最终eo=D即出现了奇数次的那个数,原因如下:
- 异或运算满足交换律
- 异或运算满足结合律
实现
public int findOdd(int[] A, int n) { |
案例五
题目
给定一个整型数组arr,其中有两个数出现了奇数次,其他数都出现了偶数次,打印这个数。要求时间复杂度O(n),空间复杂度O(1)。
分析
实现
public int[] findOdds(int[] arr, int n) { |
案例六
题目
请设计一种加密过程,完成对明文text的加密和解密工作