位操作算法基本操作1

常见的位操作

位操作符号运算规则
&两个位都为1时,结果才为1
|两个为都为0时,结果才为0
异或^两个位为0,1时,结果才为1
取反~0变1,1变0
左移<<二进位全部左移,高位丢弃,低位补零
右移>>二进位全部右移,无符号数,高位补零

细节

1.位操作只能用于整数数据,对float,double类型操作会报错;
2.位操作符运算优先级比较低,尽量使用括号确保运算顺序;
3.对于移位操作,编译器多采用算术移位,即在左移中,高位是不符号位,而逻辑移位的高位补0;

##常用的位操作 1.判断奇偶 根据最末尾是0还是1来判定奇偶性:
private void isEven(int i){
     if(i&1){
         System.out.println(i+"是奇数");
     }else{
         System.out.println(i+"是奇数");
     }
 }

2.变换符号
变换符号即为正数变成负数,负数变成正数;其中-1(1111 1111)
如12(0000 1100)-12(1111 0100),那么只需要对取反加1完成变换

private int signReverse(int i){
    return ~i+1;

3.求绝对值
对于正数绝对值为其本身,负数的绝对值相当于符号取反;只需要判断符号位是否为1来判断是否为负数

private int_abs(int i){
    int sign=(i>>31);
    return sign==0? i:(~i+1);
}

当然对于取反的操作也可以使用异或操作,整数i和0异或结果都会保持不变,和-1(0xFFFFFFFF)异或相当于取反,因此程序可以修改为:

 private int_abs(int i){
     int sign=i>>31;
     return (i^(-sign))+sign;
     }

位操作的leetcode算法应用

1.无符号整数1的个数
利用(n&1)判断n的最末尾数是否为1,然后将n向右移动一位,依次迭代,得出结果;
或者使用n&(n-1)操作,该操作将n的从左到右数位上为1进行置零;如n=12,则n&(n-1)=(0000 1100) &(0000 1011)=(0000 1000)

private int countBit(int n){
    int count=0;
    /*while(n!=0){
       int temp=(n&1);
       if(temp==1) count++;
       n=n>>1;
       }
       return count;
      */
    while(n!=0){
        n&=(n-1);
        count++;
    }
    return count;
}

2.按位反转
将一个无符号int整数类型n,高低位进行反转;
将n从右到左依次取出1,然后进行移位,再相加得到结果

private int reverseInt(int n){
    int result=0;
    for(int i=0;i<32;i++){
        result=<<1;
        if((n&1)!=0) result++;
        n=>>1;
    }
    return result;
}

3.不使用+或- 符号实现加法
在java,常可以使用异或^操作实现不带进位的和sum;
对于进位carry,只有两个加数位上都是1的情况下,才会产生进位, 从而使用&运算,再左移1位来算进位carry,
最后把两者加起来计算,重复迭代,直到进位carry为0;

private int getSum(int a,int b){
    if(b==0) return a;
    int sum=a^b;
    int carry=(a&b)<<1;
    return getSum(sum,carry);
    }
//return b==0? a : getSum(a^b,(a&b)<<1);

4.缺少的数字
给定一个包含n个不同数字的数组,从0,1,2,。n,找到数组中缺少的数字。如数组[0,2,1,4], return 3;
当然可以计算0~n的和,然后再减去数组元素的和,得到缺少的数字;
考虑到异或操作a^a=0,将数组的所有元素nums[i]与对应的下标索引i进行异或操作;由于元素数值n,没有对应的下标,所以还要与n进行xor异或操作;对数组[2,0,3],操作过程是(2^0)^(0^1)^(3^2)^3=1

private int missingNumber(int []nums){
    int xor=0;
    for(int i=0;i<nums.length;i++)
        xor=xor^nums[i]^i;
    return xor^nums.length;
    }

5.寻找大多数元素
给定大小为n的数组,找到出现次数大于n/2的元素
可以使用排序算法,其中快速排序的时间复杂度O(nlgn),Hash表其中空间复杂度O(n)
采用Moore Voting摩尔投票法,这种投票法原理(抵消思想)是将第一个数字假设为众数,计数器设置为1,比较下一个数和此数是否相等,相等则计数器加1,否则减1;当计数器的值为0时,则将当前数设置为候选众数,最后遍历数组之后,当前候选众数即为该数组的众数;

private int majorityElement(int[]nums){
    int major=nums[0],count=1;
    for(int i=1;i<nums.length;i++){
        if(count==0) {
            major=nums[i];
            count++;
        }else if(nums[i]==major){
        count++;
        }else{
         count--;
        }
    }
    return major;
}   

使用位操作来实现时间复杂度为O(n)的操作;基本思想是,若数组中的一个数major出现的次数超过n/2,那么major二进制位的1也至少出现n/2次,问题转化为求出二进制位上出现次数超过n/2,最后进行| 或操作得到结果

private int majorityElement(int[]nums){
    int major=0;
    for(int j=0,mask=1;j<32;j++,mask<<=1){
        //定义mask,判断相应的位上1出现的次数,若超过n/2,使用或操作进行连接
        int bitcount=0;
        for(int i=0;i<nums.length;i++){
            if((nums[i]&mask)!=0) bitcount++;
            if(bitcount>nums.length/2){
                major|=mask;
                break;
            }
        }
    return major;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值