劍指offer之二進制中1的個數(shù)
1 問題
實現(xiàn)一個函數(shù),輸入一個函數(shù),輸出該二進制數(shù)據(jù)中1的個數(shù)。例如9表示二進制數(shù)據(jù)1001,有2位是1,因此輸入9,該函數(shù)會輸出2。
2 分析
我們先了解下計算機里面位運算,有5種
1)& 這個是與操作,規(guī)律如下
1 & 1 = 1 1 & 0 = 0 0 & 1= 0 0 & 0 = 0
2)| 這個是或運算,規(guī)律如下
1 | 1 = 1 1 | 0 = 1 0 | 1= 1 0 | 0 = 0
3)^ 異或運算,規(guī)律如下
1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 1 = 1 0 ^ 0 = 0
4) 左移 m<<n 表示把m左移n位,在左移n位的時候,最左邊的n位丟棄,同時右邊補上n個0 比如
00001010 << 2 = 00101000
10001010 << 3 = 01010000
5) 右移 左移 m >> n 表示把m右移n位,在右移n位的時候,最右邊補上n個0 ,最左邊分2種情況,如果數(shù)字是一個無符號整形
則用0填補最左邊的n位,如果是一個有符號的數(shù)據(jù),則最左邊用數(shù)字的符號填補n個數(shù)據(jù)。如果是正數(shù),左邊補n個0,是負數(shù)左邊補n個1.
00001010 >> 2 = 00000010
10001010 >> 3 = 11110001
這里我們可以把原數(shù)據(jù)和1進行&操作,如果二進制數(shù)據(jù)尾巴進行&操作,如果包含1的話&1操作就是1,返之結果為0,然后我們把數(shù)據(jù)進行右移一位就行。
如果一個正數(shù)要除以2,我們效率最高的是把這個數(shù)據(jù)進行右移一位。
3 代碼實現(xiàn)
C++版本
#include <stdio.h>
/*
*二進制數(shù)據(jù)里面包含數(shù)字1的個數(shù)
*/
int containOneNumber(int value)
{
int count = 0;
while (value != 0)
{
//這里是(value & 1)不是(value & 0)
if (value & 1)
++count;
//這里是value = value >> 1,而不是value >> 1; 我們要用變量接收它
//不然不管就只執(zhí)行了一次也就是value除以了2,所以導致死循環(huán)。
value = value >> 1;
}
return count;
}
int main(void)
{
int result = containOneNumber(9);
printf("result is %d\n", result);
return 0;
}
java版本
public int containOneNumber(int value)
{
int count = 0;
while (value != 0)
{
if ((value & 1) != 0)
{
count++;
}
value = value >>> 1; //>>>就是java中的無符號右移
}
return count;
}
我們知道java用 >>> 是無符號右移,右移的時候,所以最高位左邊都是0,如果這個數(shù)是負數(shù)的時候,右移的話最高位會補1,
C++版本就會變成死循環(huán)。
4 優(yōu)化
方法1:
n與1做與運算,判斷n的最低位是不是為1,接著把1左移一位得到2,再和n做與運算,就能判斷n的次低位是不是1….這樣反復左移
int containOneNumber1(int n)
{
int flag = 1;
int count = 0;
while (flag != 0)
{
if ((flag & n) != 0)
{
count++;
}
flag = flag << 1;
}
return count;
}
方法2:
把一個整數(shù)減去1,再和原整數(shù)做與運算,會把該整數(shù)最右邊一個1變成0,那么一個整數(shù)的二進制表示中有
多少個1,就可以進行多少次這樣的操作
int containOneNumber1(int n)
{
int flag = 1;
int count = 0;
while (n != 0)
{
++count;
n = n & (n - 1);
}
return count;
}
5 總結
1) 把一個整數(shù)減去1,再和原整數(shù)做與運算,會把該整數(shù)最右邊一個1變成0,那么一個整數(shù)的二進制表示中有多少個1
2)n與1做與運算,判斷n的最低位是不是為1,接著把1左移一位得到2,再和n做與運算,就能判斷n的次低位是不是1….這樣反復左移
3) 如果是正整數(shù)的情況下,我們可以把正整數(shù)右移動和1進行&操作,然后再去統(tǒng)計。
作者:chen.yu
深信服三年半工作經(jīng)驗,目前就職游戲廠商,希望能和大家交流和學習,
微信公眾號:編程入門到禿頭 或掃描下面二維碼
零基礎入門進階人工智能(鏈接)