位运算相关题目

来源:互联网 发布:中国临床试验数据库 编辑:程序博客网 时间:2024/05/29 16:22

位运算:

& | 按位异或^  取反~

左移右侧补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中较大的。但是不能用任何比较判断。若两数相同,返回任意一个。给定两个整数ab,请返回较大的数

首先对数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};    }    }


原创粉丝点击