位运算相关题目

转自:https://blog.csdn.net/u012813201/article/details/75007735

(1)写一个算法,不用任何额外变量交换两个整数的值

a=a^b

b=a^b

a=a^b

————————————————————————————————————-

(2)非比较法,判断大小

对于两个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;
    }
    
 
}

————————————————————————————————————-

(3)
寻找奇数出现:时间
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;
    }
}

————————————————————————————————————-

(4)两个奇数次的数:

给定一个整型数组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};
    }
    
 
}
点赞