给定一个非负整数num
。对于0 ≤ i ≤ num
范围中的每个数字i
,计算其二进制数中的1
的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
相关阅读:汉明权重。
public int[] countBits(int num) {
int[] ans = new int[num + 1];
for (int i = 0; i <= num; ++i)
ans[i] = popcount(i);
return ans;
}
private int popcount(int x) {
int count;
for (count = 0; x != 0; ++count)
x &= x - 1; //zeroing out the least significant nonzero bit
return count;
}
x &= x - 1
将最低有效非零位清零,每次执行此操作,count
加1
,直到所有非零位都被清零为止。
返回的count
的值就是x
的二进制形式的1
的数目。
public int[] countBits(int num) {
int[] ans = new int[num + 1];
int i = 0, b = 1;
// [0, b) is calculated
while (b <= num) {
// generate [b, 2b) or [b, num) from [0, b)
while(i < b && i + b <= num){
ans[i + b] = ans[i] + 1;
++i;
}
i = 0; // reset i
b <<= 1; // b = 2b
}
return ans;
}
注意到2
、4
和8
刚好是2
的整数次方(即2
的一次方、2
的二次方和2
的三次方等等)。
以4
为例,P(4) = P(0+2^2)
,P(5) = P(1+2^2)
,P(6) = P(2+2^2)
,P(7) = P(3+2^2)
。接下来,由于4
不小于2^2
(b = 2^m > x
),所以b
乘以2
,于是P(8) = P(0+2^3)
。
public int[] countBits(int num) {
int[] ans = new int[num + 1];
for (int i = 1; i <= num; ++i)
ans[i] = ans[i >> 1] + (i & 1); // x / 2 is x >> 1 and x % 2 is x & 1
return ans;
}
以3
(其二进制形式为11
)为例,将01
转换为11
的过程:先将01
向左移动一位(实际上相当于乘以2
),然后再加1
。
注意到移位操作不会改变1
的数目,但是1
的数目会随着加1
操作而增加一个。
因此,2
的整数次方的1
的数目为1
。
仍然以3
(其二进制形式为11
)为例,将11
转换为01
的过程:先减1
,然后将10
向右移动一位(实际上相当于除以2
)。
public int[] countBits(int num) {
int[] ans = new int[num + 1];
for (int i = 1; i <= num; ++i)
ans[i] = ans[i & (i - 1)] + 1;
return ans;
}
由于x&(x-1)
会将x
的最低有效非零位清零,这样会少了一个1
,所以有P(x)=P(x&(x-1))+1
。
P(0) = 0
P(1) = P(1&(1-1))+1 = P(0) + 1 = 0 + 1 = 1
P(2) = P(2&(2-1))+1 = P(0) + 1 = 0 + 1 = 1
P(3) = P(3&(3-1))+1 = P(2) + 1 = 1 + 1 = 2
P(4) = P(4&(4-1))+1 = P(0) + 1 = 0 + 1 = 1
P(5) = P(5&(5-1))+1 = P(4) + 1 = 1 + 1 = 2
P(6) = P(6&(6-1))+1 = P(4) + 1 = 1 + 1 = 2
P(7) = P(7&(7-1))+1 = P(6) + 1 = 2 + 1 = 3
P(8) = P(8&(8-1))+1 = P(0) + 1 = 0 + 1 = 1
参考:
原文:https://www.cnblogs.com/gzhjj/p/14139109.html