比特位计数 动态规划

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将最低有效非零位清零,每次执行此操作,count1,直到所有非零位都被清零为止。
返回的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 \]

注意到248刚好是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),说明121的数目都为1
101得到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

参考:

posted @ 2020-12-15 17:17  gzhjj  阅读(115)  评论(0编辑  收藏  举报