題目:請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如把 9 表示成二進制 1001,有 2 個 1。因此如果輸入9,該函數輸出2。
位運算基本概念:
五種位運算:與(&)、或(|)、異或、左移 和 右移。
ps:其中 異或(運算符 ^),1 ^ 0 = 1; 1 ^ 1 = 0; 0 ^ 0 = 0; 0 ^ 1 = 1; 即 相同爲假,不同爲真。
左移運算符 <<,m << n,表示將 m 向左移動 n 位,並且 最左邊的 n 位被丟棄,同時最右邊補上 n 個 0。比如
00001010 << 2 = 001010 00;
// 最左邊兩位被丟棄,最右邊兩位 補 0;
10001010 << 3 = 01010 000;
右移運算符 >>,m >> n,表示將 m 向右移動 n 位,並且 最右邊的 n 位被丟棄。但最左邊的補植比較複雜,分補0 和 補1,比如
00001010 >> 2 = 00 000010; // 無符號數,最右邊兩位被捨棄,最左邊兩位 補0;
10001010 >> 3 = 111 10001; // 有符號數,最高位爲1,表示是負數,因此 最右邊三位被捨棄,最左邊三位 補1;
常規解法:(不要用 右移運算來求解,因爲若是 有符號數,會補1)
/*關鍵值flag,通過左移運算來求解,多少位循環多少次*/
int Numberof1(int n)
{
int count = 0;
unsigned int flag = 1;
while(flag)
{
if(n & flag) /** 0000 0001 ==> 0000 0010 ==> 0000 0100 ==> ...通過值 1 的那一位的移動(並且進行與運算)來判斷 n 中 1 的個數 */
count++;
flag = flag << 1;
}
return count;
}
驚喜解法:
將一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0。
/** n & (n - 1) 操作會將 n 最右邊的一個 1 變爲0,可以通過舉例來理解*/
int Numberof2(int n)
{
int count = 0;
while(n)
{
count++;
n = n & (n - 1);
}
return count;
}
相關題目:
1、用一條語句判斷一個整數是不是 2 的整數次方。
答:若一個數是 2 的整數次方,那其二進制表示中,有且只有一位是 1。使用 n&(n-1)
2、輸入兩個整數 m 和 n,計算需要改變 m 的二進制表示中的多少位才能得到 n。
答:舉例,使用 異或運算,統計異或結果中 1 的個數。
/*點滴積累,我的一小步O(∩_∩)O~*/