計算十進制數字在二進制表示 1 的個數html
舉個例子:算法
對於這個題目比較容易想到的是以下代碼:數組
int count = 0; while(n != 0) { if(n % 2 == 1) { count++; } n = n >> 1; }
上述代碼主要作了兩個步驟:spa
n % 2
表示對數字求模運算,也就是計算二進制的末尾是 1 仍是 0,若是二進制的末尾是 1 ,則 count 自增,count 表示的是二進制表示 1 的個數;n = n >> 1
表示把二進制往右移走一位,好比十進制數字 7 的二進制表示是 111 ,那麼經過右移一位後,則變成 011。這個解決方式雖然能計算出二進制表示 1 的個數,可是咱們能夠發現這個解法的時間複雜度是 O(logn),好比當 n 爲 7 時,它的二進制表示是 111,那麼它將會循環 3 次,也就是很是接近 log 以 2 爲底 7 的對數的值。code
程序讀入一個整數 n,假設 n 不會大於 1000,請輸出 1 到 n 每一個數字的二進制表示 1 的個數。htm
可能有的小夥伴說,這題目二還不簡單?直接把上面的解法,增長個 for 循環不就得了。blog
int main() { int i, j, n, count; scanf("%d", &n); for(i = 1; i <= n; i++) { j = i; count = 0; while(j != 0) { if(j % 2 == 1) { count++; } j = j >> 1; } printf("number:%d, count:%d\n", i, count); } return 0; }
假設輸入 7,則輸出結果:class
number:1, count:1 number:2, count:1 number:3, count:2 number:4, count:1 number:5, count:2 number:6, count:2 number:7, count:3 number:8, count:1
沒錯,用上述的解法增長個 for 循環,確實能夠解決題目二的要求,這值得鼓勵,可是程序的時間複雜度是時間複雜度 O(nlogn) ,運行效率不高,因此咱們必需要有種精神,就是要用時間複雜度最少的方式去解決算法的問題,這樣才能一次一次的進步。效率
請先觀察下面的位運算性質:變量
y = x & (x - 1)
咱們看到,x
和與 x -1
這兩個數字作按位與運算,因此咱們要以二進制的角度去思考這個問題。
好比:
x
是 3,它的二進制是 011;x - 1
就是 2,它的二進制是 010;x & (x - 1)
運算後的二進制就是 010。那麼 x & (x - 1)
實際效果等效於去掉 x
二進制表示中的最後一位 1,從而咱們發現原來 y
變量與 x
變量在二進制表示中,只差一個 1。
若是咱們用一個數組 f
記錄相應數字二進制表示中 1 的數量,那麼 f[i]
數組存放的值是 i
這個數字二進制表示中 1 的數量,從而咱們能夠推導獲得 f[i] = f[i & (i - 1)] + 1
,也就是說 i
數字比 i & (i - 1)
數字的二進制表示中的 1 的數量要多一個,這樣咱們經過一步計算就獲得 f[i]
的結果,也就是相應數字二進制表示中 1 的數量結果。
代碼以下:
int main() { int n,i; int f[1001]; f[0] = 0; scanf("%d", &n); for(i = 1; i <= n; i++) { f[i] = f[i & (i - 1)] + 1; } for(i = 1; i <= n; i++) { printf("%d ", f[i]); } printf("\n"); return 0; }
這個程序的過程以下:
n
,表明要求解的範圍;n
次,每一次經過 f[i] = f[i & (i - 1)] + 1
計算獲得 f[i]
的值,也就是數字的二進制表示 1 的個數;n
中每一個數字二進制表示中 1 的個數。針對這個解法,程序的時間複雜度是 O(n)。
原文出處:https://www.cnblogs.com/xiaolincoding/p/12219909.html