比特位计数 动态规划
1. 题目描述
给定一个非负整数num
。对于0 ≤ i ≤ num
范围中的每个数字i
,计算其二进制数中的1
的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
2. 题解
2.1 汉明权重
相关阅读:汉明权重。
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
的数目。
2.2 动态规划
2.2.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;
}
\[P(x+b)=P(x)+1, b = 2^m>x
\]
\[P(0) = 0
\]
\[P(1) = P(0+2^0)=P(0)+1 = 1
\]
\[P(2) = P(0+2^1)=P(0)+1 = 1
\]
\[P(3) = P(1+2^1)=P(1)+1 = 2
\]
\[P(4) = P(0+2^2)=P(0)+1 = 1
\]
\[P(5) = P(1+2^2)=P(1)+1 = 2
\]
\[P(6) = P(2+2^2)=P(2)+1 = 2
\]
\[P(7) = P(3+2^2)=P(3)+1 = 3
\]
\[P(8) = P(0+2^3)=P(0)+1 = 1
\]
注意到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)
。
2.2.2 最低有效位
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;
}
\[P(x)=P(x/2)+(x\quad mod\quad2)
\]
\[P(0) = 0
\]
\[P(1) = P(0)+(1\quad mod \quad2) = 0 + 1 = 1
\]
\[P(2) = P(1)+(2\quad mod \quad2) = 1 + 0 = 1
\]
\[P(3) = P(1)+(3\quad mod \quad2) = 1 + 1 = 2
\]
\[P(4) = P(2)+(4\quad mod \quad2) = 1 + 0 = 1
\]
\[P(5) = P(2)+(5\quad mod \quad2) = 1 + 1 = 2
\]
\[P(6) = P(3)+(6\quad mod \quad2) = 2 + 0 = 2
\]
\[P(7) = P(3)+(7\quad mod \quad2) = 2 + 1 = 3
\]
\[P(8) = P(4)+(8\quad mod \quad2) = 1 + 0 = 1
\]
将01
向左移动一位(实际上相当于乘以2
),得到10
(即2
),说明1
和2
的1
的数目都为1
。
将10
加1
得到11
(即3
),所以P(3)=P(1)+1
。
注意到移位操作不会改变1
的数目,但是1
的数目会随着加1
操作而增加一个。
因此,2
的整数次方的1
的数目都为1
。
2.2.3 最后设置位
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
参考: