和1 与 为1,则为1,否则为0,因此用 与 操作来判断是否为1
思路1:
首先应该想到的是,先判断最右边的是否为1,然后整体右移一位,这样原来右边第二个数就被移动到最右边了,再判断;反复这样,就可以得到1的个数。
关键是这样的想法,在进行负数的个数统计时,会有问题,因为负数的二进制首位为1,移位后,为了保证还是负数,计算机会在首位再补1,这样不管你怎么移动,首位永远是1,陷入死循环。因此需要转变思路。
public class Solution { public int NumberOf1(int n) { int count = 0; while (n != 0) { if ((n & 1) == 1) { count++; } n = n >> 1;//把n的2进制形式往右推一位 } return count; } }
思路2:基于思路1的改进,既然原来的数右移可能会出问题,那就不移位。那原来的数不右移了,我用另一个数左移来相 与(相对运动可还行)。
flag 变化是 1 10 100 1000 ...
直到变成1000000..... 最终计算机认为你的首位是负数的标志时,再移动一次后,就全变成了0。此时为循环终止条件
那么代码如下
public class Solution { public int NumberOf1(int n) { int count = 0; int flag = 1; while(flag != 0){ if((n & flag) != 0){ //flag只有首位是1,其余位是0,相与为0,说明比较的当前位是0 count ++; } flag = flag << 1; } return count; } }
思路3:一个数的二进制减1后,原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 如1100 减1 变 1011。两数相与是1000,则这样的一次操作去掉了最右边的1(1100百位的1没了),利用这个规律进行解题。
public class Solution { public int NumberOf1(int n) { int count = 0; while(n!= 0){ count++; n = n & (n - 1); } return count; } }