动态规划+二进制运算
题目链接:
比特位计数 来自LeetCode
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
解题方法参考LeetCode解题
方法一:
针对任意整数k,可以转为二进制.将k和k-1进行&运算.这样就会将最后一个是1的位变为0.每次将&的结果重新赋值给k.每一次赋值,进行计数+1.直到K变为了0,得到的计数值,就是当前数字中二进制1的个数.
例如:123:
| 十进制 | 相邻位 | &结果 | ||
| 1 | 1111011 | 1111010 | 1111010 | |
| 2 | 1111010 | 1111001 | 1111000 | |
| 3 | 1111000 | 1110111 | 1110000 | |
| 4 | 1110000 | 1101111 | 1100000 | |
| 5 | 1100000 | 1011111 | 1000000 | |
| 6 | 1000000 | 0111111 | 0000000 |
最后一共执行了六次位运算,所以二进制中1的结果为6.
遍历范围中的每个数,就可以得到最终结果.
代码:
public class Solution1 {
public int[] countBits(int num) {
int[] result = new int[num+1];
for(int i = 0;i<=num;i++){
result[i] = calcCnt(i);
}
return result;
}
private int calcCnt(int number){
int cnt=0;
while(number!=0){
number &=(number-1);
cnt++;
}
return cnt;
}
}
方法二:
动态规划+从低往高计算.
二进制最基本的0和1,前面增加1,变为了(10)2=4,(11)2=3.
同样的,根据1~4的二进制,前面增加1,可以变为5~8.
| 00 | 0 | 100 | 4 |
| 01 | 1 | 101 | 5 |
| 10 | 2 | 110 | 6 |
| 11 | 3 | 111 | 7 |
所以可以通过递推公式求出范围中所有数字的1的个数.
P(x+b) = P(x)+1,b=2m>x.
P(x)代表x中1的个数.
b表示增加的基数,这个基数一定是2的次幂.
仍旧按照上面例子来说:
(0,1)中1的个数是(2,3)中1的个数-2,
(0,3)中1的个数是(4,7)中1的个数-4.
java代码:
public class Solution2 {
public int[] countBits(int num) {
int[] res = new int[num+1];
int i = 0;
int b = 1;
while(b<=num){
while(i<b&&i+b<=num){
res[i+b] = res[i]+1;
}
i = 0;
b<<=1;
}
return res;
}
}
方法三:
动态规划+数字移位.
对于一个数x,执行右移后会变为x/2.
如果x本身为偶数,右移后1的个数是不变的.
如果x本身是奇数,右移后,1的个数会少一个.
所以P(x) = P(x/2)+mod(x,2).
java代码:
public class Solution3 {
public int[] countBits(int num) {
int[] res = new int[num+1];
for(int i = 0;i<=num;i++){
res[i] = res[i/2]+i%2;
}
return res;
}
}
方法四:
动态规划+最低的1位归零
实际内容与方法一相似.针对数字x,执行了x&(x-1)后,x的最低1的位会变为0;
所以P(x) = P(x&(x-1))+1;
从小到大进行所有数字遍历即可.
java代码:
public class Solution4 {
public int[] countBits(int num) {
int[] res = new int[num+1];
for(int i = 1;i<=num;i++){
res[i] = res[i&(i-1)]+1;
}
return res;
}
}

浙公网安备 33010602011771号