整數(shù)的二進(jìn)制表示中1的個(gè)數(shù)
題目:輸入一個(gè)整數(shù),求該整數(shù)的二進(jìn)制表達(dá)中有多少個(gè)1。例如輸入10,由于其二進(jìn)制表示為1010,有兩個(gè)1,因此輸出2。
分析:這是一道很基本的考查位運(yùn)算的面試題。包括微軟在內(nèi)的很多公司都曾采用過這道題。
一個(gè)很基本的想法是,我們先判斷整數(shù)的最右邊一位是不是1。接著把整數(shù)右移一位,原來處于右邊第二位的數(shù)字現(xiàn)在被移到第一位了,再判斷是不是1。這樣每次移動(dòng)一位,直到這個(gè)整數(shù)變成0為止,F(xiàn)在的問題變成怎樣判斷一個(gè)整數(shù)的最右邊一位是不是1了。很簡(jiǎn)單,如果它和整數(shù)1作與運(yùn)算。由于1除了最右邊一位以外,其他所有位都為0。因此如果與運(yùn)算的結(jié)果為1,表示整數(shù)的最右邊一位是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;
}
可能有讀者會(huì)問,整數(shù)右移一位在數(shù)學(xué)上是和除以2是等價(jià)的。那可不可以把上面的代碼中的右移運(yùn)算符換成除以2呢?答案是最好不要換成除法。因?yàn)槌ǖ男时纫莆贿\(yùn)算要低的多,在實(shí)際編程中如果可以應(yīng)盡可能地用移位運(yùn)算符代替乘除法。
這個(gè)思路當(dāng)輸入i是正數(shù)時(shí)沒有問題,但當(dāng)輸入的i是一個(gè)負(fù)數(shù)時(shí),不但不能得到正確的1的個(gè)數(shù),還將導(dǎo)致死循環(huán)。以負(fù)數(shù)0x80000000為例,右移一位的時(shí)候,并不是簡(jiǎn)單地把最高位的1移到第二位變成0x40000000,而是0xC0000000。這是因?yàn)橐莆磺笆莻(gè)負(fù)數(shù),仍然要保證移位后是個(gè)負(fù)數(shù),因此移位后的最高位會(huì)設(shè)為1。如果一直做右移運(yùn)算,最終這個(gè)數(shù)字就會(huì)變成0xFFFFFFFF而陷入死循環(huán)。
為了避免死循環(huán),我們可以不右移輸入的數(shù)字i。首先i和1做與運(yùn)算,判斷i的最低位是不是為1。接著把1左移一位得到2,再和i做與運(yùn)算,就能判斷i的次高位是不是1……這樣反復(fù)左移,每次都能判斷i的其中一位是不是1;诖耍覀兊玫饺缦麓a:
///////////////////////////////////////////////////////////////////////
// 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;
}
另外一種思路是如果一個(gè)整數(shù)不為0,那么這個(gè)整數(shù)至少有一位是1。如果我們把這個(gè)整數(shù)減去1,那么原來處在整數(shù)最右邊的1就會(huì)變成0,原來在1后面的所有的0都會(huì)變成1。其余的所有位將不受到影響。舉個(gè)例子:一個(gè)二進(jìn)制數(shù)1100,從右邊數(shù)起的第三位是處于最右邊的一個(gè)1。減去1后,第三位變成0,它后面的兩位0變成1,而前面的1保持不變,因此得到結(jié)果是1011。
我們發(fā)現(xiàn)減1的結(jié)果是把從最右邊一個(gè)1開始的所有位都取反了。這個(gè)時(shí)候如果我們?cè)侔言瓉淼恼麛?shù)和減去1之后的結(jié)果做與運(yùn)算,從原來整數(shù)最右邊一個(gè)1那一位開始所有位都會(huì)變成0。如1100&1011=1000。也就是說,把一個(gè)整數(shù)減去1,再和原整數(shù)做與運(yùn)算,會(huì)把該整數(shù)最右邊一個(gè)1變成0。那么一個(gè)整數(shù)的二進(jìn)制有多少個(gè)1,就可以進(jìn)行多少次這樣的操作。
這種思路對(duì)應(yīng)的代碼如下:
///////////////////////////////////////////////////////////////////////
// Get how many 1s in an integer's binary expression
///////////////////////////////////////////////////////////////////////
int NumberOf1_Solution3(int i)
{
int count = 0;
while (i)
{
++ count;
i = (i - 1) & i;
}
return count;
}
相關(guān)推薦:
北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |