行文脈絡
- 解法一——除法
- 解法二——移位
- 解法三——高效移位
- 解法四——查表
- 擴展問題——異或后轉化為該問題
對於一個字節(8bit)的變量,求其二進制“1”的個數。例如6(二進制0000 0110)“1”的個數為2,要求算法效率盡量高。
解法一
對於二進制數來說,除一個2,就少一位,可以判斷這個少的位來確定“1”的個數。
例如:6(0000 0110)
0000 0110 / 2 = 0000 0011 ----少的一位為0
0000 0011 / 2 = 0000 0001 ----少的一位為1
0000 0001 / 2 = 0000 0000 ----少的一位為1
操作數數已經為0,到此結束
參考代碼
int Count_1(int val) { int num = 0; while(val) { if(val % 2 != 0) //用取模獲得去除的一位 ++num; val /= 2; } return num; }
性能:時間復雜度O(log2v),即二進制數的位數;空間復雜度O(1)
解法二
對於二進制數來說,除法是用移位完成。
例如:6(0000 0110)
0000 0110 >> 1 = 0000 0011 ----少的一位為0
0000 0011 >> 1 = 0000 0001 ----少的一位為1
0000 0001 >> 1 = 0000 0000 ----少的一位為1
操作數數已經為0,到此結束
參考代碼
int Count_2(int val) { int num = 0; while(val) { if(val & 1 != 0) //用與1與獲得移除的一位 ++num; val >>= 1; } return num; }
性能:時間復雜度O(log2v),即二進制數的位數;空間復雜度O(1)
解法三
對於上述算法,有個問題,比如1000 0000,大把的時間用在沒用的0上,最好尋求一種直接判斷“1的個數。
通過觀察可以找到規律:對於數a, a = a & (a-1)就可以去除a的最后一個1
例如:6(0000 0110)
0000 0110 & 0000 0101 = 0000 0100
0000 0100 & 0000 0011 = 0000 0000
操作數數已經為0,到此結束
參考代碼
int Count_3(int val) { int num = 0; while(val) { val &= (val -1); ++num; } return num; }
性能:時間復雜度O(M),即二進制中“1”的個數,空間復雜度O(1)
解法四
查表法,把0~255這256個數的結果全部存儲在數組中,val直接作為下標,countTable[val]即為結果。典型的用空間換時間。
參考代碼
int Count_5(int val) { int countTable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; return countTable[val]; }
性能:時間復雜度:O(1), 空間復雜度O(N)
整個程序執行參考

#include<iostream> using namespace std; int Count_1(int val) { int num = 0; while(val) { if(val % 2 != 0) ++num; val /= 2; } return num; } int Count_2(int val) { int num = 0; while(val) { if(val & 1 != 0) ++num; val >>= 1; } return num; } int Count_3(int val) { int num = 0; while(val) { val &= (val -1); ++num; } return num; } int Count_5(int val) { int countTable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; return countTable[val]; } int main() { int a = 6, b = 255; cout << "Num of 1:" << Count_1(a) << endl; cout << "Num of 1:" << Count_2(a) << endl; cout << "Num of 1:" << Count_3(a) << endl; cout << "Num of 1:" << Count_5(b) << endl; cout << "Num of 1:" << Count_1(b) << endl; cout << "Num of 1:" << Count_2(b) << endl; cout << "Num of 1:" << Count_3(b) << endl; cout << "Num of 1:" << Count_5(b) << endl; }
結果
擴展問題
1. 給定兩個正整數(二進制表示)A、B,如何快速找出A和B二進制表示中不同位數的個數。
思路
首先A和B進行異或操作,然后求得到的結果中1的個數(此問題)。
2. 判斷一個數是否是2的冪
bool powerof2(int n) { return ((n & (n-1)) == 0); }