剑指 Offer II 003. 前 n 个数字二进制中 1 的个数
创建时间: November 24, 2021 9:59 AM
最后编辑时间: November 24, 2021 2:03 PM
标签: 位运算, 动态规划
网址: https://leetcode-cn.com/problems/w3tCBm/
难度: 简单
题目
输入一个非负数n,请计算0到n之间每个数字的二进制形式中1的个数,并输出一个数组。例如,输入的n为4,由于0、1、2、3、4的二进制形式中1的个数分别为0、1、1、2、1,因此输出数组[0,1,1,2,1]。
分析
最直观的解法是使用一个for循环来计算从0到n的每个整数i的二进制形式中1的个数。于是问题转换成如何求一个整数i的二进制形式中1的个数。
计算整数的二进制形式中 1 的个数
计算整数i的二进制形式中1的个数的一种比较高效的方法是每次用i&(i-1)将整数i的最右边的1变成0。整数i减去1,那么它最右边的1变成0,而其左边所有位都保持不变,如果它的右边还有0,则右边所有的0都变成1。下面对i和i-1进行与运算,相当于将其最右边的1变成0。
以二进制的1100为例,它减去1的结果是1011。1100和1011的与运算的结果正好是1000。二进制的1100最右边的1变为0,结果刚好就是1000。
class Solution {
public int[] countBits(int n) {
int[] res=new int[n+1];
for(int i=0;i<=n;i++){
res[i]=oneBits(i);
}
return res;
}
//计算整数的二进制形式中1的个数
public int oneBits(int num){
int res=0;
while(num!=0){
num=num & (num-1);
res++;
}
return res;
}
}
使用动态规划
题目要求计算一个连续整数序列的二进制1的个数,因此可以利用已经计算出的结果来计算当前数的结果。已知i&(i-1) 是将i 的二进制形式中最右边的1变成0,也就是说,整数i的二进制形式中1的个数比i&(i-1)的二进制形式中1的个数多1。因此有以下表达式
\[dp[i] =
\begin{cases}
0, & i=0 \\
dp[i\&(i-1)]+1, & i\geq1
\end{cases}\]
class Solution {
public int[] countBits(int n) {
int[] result=new int[n+1];
for(int i=1;i<=n;++i){
result[i]=result[i&(i-1)]+1;
}
return result;
}
}

浙公网安备 33010602011771号