【算法】 Bit Operation(位运算)

今天做到关于位运算的算法题的时候发现自己好像是一点也不是很了解。于是就开始找了有关位运算的题目开始补。

#第一题:
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示


首先要了解以下的基本的位操作符:

符号含义描述运算规则
&两个位都为1时,结果才为1
I两个位都为0时,结果才为0
^异或两个位相同为0,相异为1
~取反0变1,1变0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

##分析:
这是牛客上的一道题目,假设
5 = 0000 0101
我们可以循环做移位运算5<<1后,与1做与运算,若等于1则count++。这样做确实是可以暂时得到我们想要的答案。

public static int NumberOf1_CanNotUse(int n) {
	int count = 0;
	while (n != 0) {
		if ((n & 1) == 1) {
			count++;
		}
		n = n >> 1;
	}
	return count;
}  

但是我们我们的无符号整数时包括负数的,负数用补码表示,假设n=-5时,其补码为-5=1111 1011,当-5>>1时,补码向右移的时候高位加1,这会导致我们的count++至+∞导致死循环。
所以我们应该换一下时目标数字往左移。即-5<<1,这样就会很好的解决了我们的问题,因为不管是正数还是负数<<1的时候都是在末位加0.

 private static int NumberOf1_low(int n) {
    int count = 0;
    int flag = 1;
    while (flag != 0) {
        if ((n & flag) != 0) {
            count++;
        }
        flag = flag << 1;
    }
    return count;
}

####最优解:

public static int NumberOf1(int n) {
    int count = 0;
    while (n != 0) {
        ++count;
		//通过执行 n&(n-1) 操作来消除 n 末尾的 1 ,消除了多少次,就说明有多少个 1 。
        n = (n - 1) & n;
    }
    return count;
}

#第二题:
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
##分析:
观察二次幂:
2=1
4=10
8=100
16=1000
32=10000

可以很容易的看出来二次幂的规律,只有在其高位有1,其余都是为0。所以我们只需要将数字向右移即可

public boolean NumberOf1(int n) {
	int cnt = 0;
    while (n > 0) {
        cnt += (n & 1);
        n >>= 1;
    }
    return cnt == 1;
}

但是后来看到了更加简单的例子,emmm大佬还是很多的啊!我等渣渣还是得好好努力。

public boolean NumberOf1(int n) {
		return (n>0) && ((n&(n-1)) == 0);
}

#第三题:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
##分析:
将所有元素做异或运算,即a[1] ^ a[2] ^ a[3] ^ …^ a[n],所得的结果就是那个只出现一次的数字

public int NumberOf1(int[] m) {
	int result = 0;
	for (int i : m) {
		result ^= i;
    }
	return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值