基础:
1、左移运算
左移运算符m<<n表示把m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在右边补上n个0。比如:
00001010<<2=00101000
10001010<<3=01010000
2、右移运算
右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一些。如果数字是一个无符号数值,则用0填充最左边的n位。也就是说如果数字原先是一个正整数,则右移之后,直接在最左边补上n个0;如果数字原先是负数,则右移之后需要在最左边补上n个1。比如:
00001010>>2=00000010
10001010>>3=11110001
3、&和&&的区别
&:表示按位与,一般用于计算二进制的按位与运算
&&:表示逻辑与,两边都为真才是真。
题目:
输入一个整数,输出该数二进制表示中1的个数,其中负数用补码表示。
思路:
先判断整数二进制表示中最右边一位是不是1,接着把输入的整数右移,此时原来处于从右边数起的第二位被移到最右边了,再判断是不是1。这样每次移动一位,直到整个整数变成0为止。但是对于输入数据是负数的时候,会陷入死循环。因此,为了避免陷入死循环,我们可以不右移输入的数字i。首先把i和1做与运算,判断i的最低位是不是1。接着把1左移一位得到2,再和i做与运算,就能判断i的次低位是不是1......这样反复左移,每次都能判断i的其中一位是不是1。
代码:
public class Solution {
public int NumberOf1(int n) {
//通过每次将flag向左移动1位之后,与n进行按位&操作判断该位置是否为1
int flag=1;
int count=0;
while(flag!=0){
if((n&flag)!=0){//判断条件为&操作后的值不等于0
count++;
}
flag=flag<<1;//向左移动
}
return count;
}
}
厉害的做法;
思路:
如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。
1、假设这个数的最右边一位是1,则减去1之后,最后一位变成0,而其他所有位都保持不变。也就是最后一位相当于做了取反操作,由1变成0。
2、假设最后一位不是1而是0,如果该整数的二进制表示中最右边1位于第m位,那么减去1时,第m位由1变成0,而第m位之后的所有0都变成1,整数中第m位之前的所有位都保持不变。例如,1100,从0开始表示下标,则1位于2号位置,减去1之后,2号位置变为0,他后面的两位变成1,前面的1保持不变,所以结果是1011。
3、在前面两种情况中,我们发现把一个整数减去1,都是把最右边的1变成0。如果它的右边还有0的话,所有的0都变成1,而它左边所有位都保持不变。接下来我们把一个整数和它减1的结果做按位与运算,相当于把它最右边的1变成0。例如,1100,减去1之后是1011,1100与1011做按位与运算结果是1000,把1100的最右边的1变成了0,结果正好就是1000。
总结就是:把一个整数减去1,再和原来整数做与运算,会把该整数最右边一个1变成0。
代码:
public class Solution {
public int NumberOf1(int n) {
int count=0;
while(n!=0){
count++;
n=n&(n-1);
}
return count;
}
}