題目:輸入一個整數,求該整數的二進制表達中有多少個1。
例如輸入10,由於其二進制表示爲1010,有兩個1,因此輸出2。
分析:
這是一道很基本的考查位運算的面試題。
包括微軟在內的……
一個很基本的想法是,我們先判斷整數的最右邊一位是不是1。
接着把整數右移一位,原來處於右邊第二位的數字現在被移到第一位了,
再判斷是不是1。
這樣每次移動一位,直到這個整數變成0爲止。
現在的問題變成怎樣判斷一個整數的最右邊一位是不是1了。
很簡單,如果它和整數1作與運算。由於1除了最右邊一位以外,其他所有位都爲0。
因此如果與運算的結果爲1,表示整數的最右邊一位是1,否則是0。*/
得到的代碼如下:
///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution1(int i)
{
int count = 0;
while(i)
{
if(i & 1)
count ++;
i = i >> 1;
}
return count;
}
可能有讀者會問,整數右移一位在數學上是和除以2是等價的。
那可不可以把上面的代碼中的右移運算符換成除以2呢?答案是最好不要換成除法。
因爲除法的效率比移位運算要低的多,
在實際編程中如果可以應儘可能地用移位運算符代替乘除法。
這個思路當輸入i是正數時沒有問題,但當輸入的i是一個負數時,
不但不能得到正確的1的個數,還將導致死循環。
以負數0x80000000爲例,右移一位的時候,
並不是簡單地把最高位的1移到第二位變成0x40000000,
而是0xC0000000。這是因爲移位前是個負數,仍然要保證移位後是個負數,
因此移位後的最高位會設爲1。
如果一直做右移運算,最終這個數字就會變成0xFFFFFFFF而陷入死循環。
爲了避免死循環,我們可以不右移輸入的數字i。
首先i和1做與運算,判斷i的最低位是不是爲1。
接着把1左移一位得到2,再和i做與運算,就能判斷i的次高位是不是1……
這樣反覆左移,每次都能判斷i的其中一位是不是1。基於此,我們得到如下代碼:
///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution2(int i)
{
int count = 0;
unsigned int flag = 1;
while(flag)
{
if(i & flag)
count ++;
flag = flag << 1;
}
return count;
}
前面是從其他地方copy的,
方法三:
int func(int n)
{
int num = 0;
while (n != 0)
{
n = n &(n-1);
num++;
}
return num;
}