位运算:
& | 按位异或^ 取反~
左移右侧补0相当*2: << 右移左侧补符号位相当/2 :>>
右移左侧补00:>>>
相关问题:布隆过滤器
(1)不安全网页的黑名单里有100亿个数据,每一个网页的URL最多占用64B。要求实现一种过滤系统,可以根据网页的URL判断是否在这个黑名单中。系统允许有万分之一的失误率。且额外的空间不能超过30GB。
首先100亿个URL共占 64 * 10 ^10bit 约为640GB的空间,远超过题目要求30G。该过滤系统的空间要求比较高,且能够容忍一定的错误率,所以我们往布隆过滤器考虑。
类似的网页黑名单系统、垃圾邮件过滤系统、爬虫的网址判断重复系统...对空间要求严格且容忍一定程度的失误率,那么都可以考虑布隆过滤器。
用布隆过滤器处理所有URL,集合生成完毕。在检查阶段,URL=a,对url进行k个hash函数计算,然后去检查数组中对应位置是否全部为1。A是黑名单一定会被检查出来,a不是黑名单,可能会误判。
如果数组大小m相对于样本数量n过小,失误率p增加。
N=100亿 p=0.01%,样本大小不影响布隆过滤器大小,是哈希函数能够接收参数的大小。
最终失误率小于0.01%。
Bloom Filter 布隆过滤器
用途: 布隆精确代表一个集合(精确程度由具体设计而定 100%不可能),判断一个元素是否在一个集合中、检查一个英语单词是否正确拼写;
原理: 位数组bitarray[m]+k个不同的Hash函数。数组初始化为0,有k个不同的hash函数输出域>=m,对其%m,在0~m-1对应位置上置1。查询时判断这k个位(有0则该元素肯定不在集合中,都为1则该元素有可能在集合中)。
优点: 有良好的空间效率和时间效率,插入、查询O(n),安全性高,正确率也很高。
缺点: 正确率低,有可能不在集合中的元素在位数组查询的位得到都为1。
-------------------------------------------------------------------------------------------------------------
(2)写一个算法,不用任何额外变量交换两个整数的值
a=a^b
b=a^b
a=a^b
-------------------------------------------------------------------------------------------------------------
(3)非比较法,判断大小对于两个32位整数a和b,请设计一个算法返回a和b中较大的。但是不能用任何比较判断。若两数相同,返回任意一个。给定两个整数a和b,请返回较大的数。
首先对数n右移31位,再&1获得符号位,判断c=a-b的符号位即可。
注意当a为负b为正时,a-b可能产生溢出。
public class Compare {
public int getMax1(int a,int b){//当a为负 b为正时,a-b可能会产生溢出,高位的符号位错误,所以getMax方法更安全。
int c=a-b;
int returnA=sign(c);//获取想减结果的符号位
int returnB=flip(returnA);
return a*returnA+b*returnB;
}
public int getMax(int a, int b) {
int c=a-b;
int sa=sign(a);
int sb=sign(b);
int sc=sign(c);//获取想减结果的符号位
int difSab=sa^sb;//a b不同号 0---同号 1---不同号
int sameSab=flip(difSab);//a b同号: 0--不同号 1--同号
int returnA=difSab*sa+sameSab*sc;//如果ab不同号:returnA=sa,sameSab=0,不会用到sc
int returnB=flip(returnA);//如果ab同号:sameSab=1,会用到sc。这里因为ab同号所以其想减后不会溢出。
return a*returnA+b*returnB;
}
public int sign(int n){//返回0--负数 1---非负
return flip((n >> 31) & 1);//带符号位右移31位,&1是获取符号位
}
public int flip(int n){
return n^1;
}
}
-------------------------------------------------------------------------------------------------------------
(4) 寻找奇数出现:时间 O(n), 空间 O(1)有一个整型数组A,其中只有一个数出现了奇数次,其他的数都出现了偶数次,请打印这个数。要求时间复杂度为O(N),额外空间复杂度为O(1)。给定整形数组A及它的大小n,请返回题目所求数字
思路:因t^t=0,t^0=t;且异或满足交换律和结合律。所以int e=0,依次e^a[i]异或,最后结果,即为出现奇数次的数。
public class OddAppearance {
public int findOdd(int[] a, int n) {
// write code here
int e=0;
for(int i=0;i<n;i++){
e=e^a[i];
}
return e;
}
}
-------------------------------------------------------------------------------------------------------------
(5)两个奇数次的数:给定一个整型数组arr,其中有两个数出现了奇数次,其他的数都出现了偶数次,找到这两个数。要求时间复杂度为O(N),额外空间复杂度为O(1)。
给定一个整形数组arr及它的大小n,请返回一个数组,其中两个元素为两个出现了奇数次的元素,请将他们按从小到大排列
思路:首先和(4)题一样,e=e^a[i]最终得到e=m^n(假定m n是出现奇数次的两个数),那么e-->二进制,肯定存在值为1的位置,假定第k位的值为1,说明m n在第k位上不同。
假定m的第k位为1,n的第k位为0。e2=e2^x;x是数组中第k位为1的所有数,那么最终e2=m。而n=e^e2
public class OddAppearance {
public int[] findOdds(int[] arr, int n) {
int e1=0;
for(int i=0;i<n;i++){
e1=e1^a[i];
}
int rightOne=e1&(~e1+1);//从右数 e1中第一个值为1的位置。**************第k位
int e2=0;
for(int cur:arr){
if((cur&rightOne)==1){
e2=e2^cur;
}
}
int m=e2;
int n=e2^e1;
int small=Math.min(m,n);
int large=Math.max(m,n);
return new int[]{small,large};
}
}