算法-LeetCode-整数的二进制表示中1的个数
题目
输入一个,输出该数二进制表示中1的个数。 其中负数用补码表示。 说明:对于负数的二进制码,比如-1(由于java中int 为4个直接,总共32位,这里方便表示只取8位) 原码:-1=1000 0001 (最高位为符号位,负数用1表示) 反码:-1=1111 1110 (除了最高位的符号位,其余的全部取反) 补码:-1=1111 1111 (把反码加一,则为补码) 实际上,对于负数,他的二进制表示为补码。所以java中int类型-1,它的二进制全部是1,也就是32位1
解法一:使用与运算符,先看代码
public int NumberOf2(int n) { int count = 0; while(n != 0){ count++; n = n & (n-1); } return count; }
这个有点不好理解,举个例子,n为负3。 *原码:-3=1000 0011 *反码:-3=1111 1100 *补码:-3=1111 1101
所以-3的二进制为111111101,而-3-1=-4, *原码:-4=1000 0100 *反码:-4=1111 1011 *补码:-4=1111 1100
1000 0101 1111 1011 所以-3&-4(1111 1101 & 1111 1100)结果的二进制为1111 1100 = -4 同理-4&-5(1111 1100 & 1111 1011)结果的二进制为1111 1000 = -8 同理-8&-9(1111 1000 & 1111 0111)结果的二进制为1111 0000 = -16 同理-16&–17(1111 0000 & 1110 1111)结果的二进制为1111 0000 = -16 直到最后(1100 0000 & 1011 1111)结果的二进制为 1000 0000 即为-0=0
所以这个比较巧妙的是 n&n-1这个问题,不怎么好理解。
解法二:使用移位,看代码
public int NumberOf1(int n) { if(n == 0) return 0; int count = 0; /**当n为负数,去除最高位的符号位(即-1),将n变为正数*/ if(n < 0){ count++; //先左移一位,将符号位的1挤掉,再无符号右移一位,高位补0,即为正数 n = (n<<1) >>> 1; } do{ //n和1做与运算,即求最低位是否为1 if((n&1) == 1) count ++ ; //然后n右移,挤掉最低位 }while((n = n>>>1) > 0); return count; }
这个思路比较好理解,不过要清楚java中的普通右移为>>,而无符号右移为>>>。普通右移符号位是不跟着移动的。