计算十进制数字在二进制表示 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