题目描述
.前 n 个数二进制中 1 的个数
给定一个非负整数 n ,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。
示例 1:
输入: n = 2输出: [0,1,1]解释:0 --> 01 --> 12 --> 10
示例 2:
输入: n = 5输出: [0,1,1,2,1,2]解释:0 --> 01 --> 12 --> 103 --> 114 --> 1005 --> 101
说明 :
进阶:
给出时间复杂度为 O(n*sizeof(integer)) 的解答非常容易。但你可以在线性时间 O(n) 内用一趟扫描做到吗?
要求算法的空间复杂度为 O(n) 。
你能进一步完善解法吗?要求不使用任何内置函数来执行此操作。
解题思路
位运算
比如1100,实值为12
右移一位之后为0110,实值为6
2 * 右移结果 = 原数
此时右移损失的是0,也就是此时最低为为0
对右移结果再次进行右移,直到右移结果为0为止。
由此可以得到二进制表示中1个数。
动态规划
对于偶数 其二进制表示的最低位必为0,则其二进制表示中1的个数与其1/2相同
也就是i为偶数 res[i] = res[i/2]
对于奇数,他的最低位一定为1,刚好就比他前一个数(偶数)多了一个低位1
res[i] = res[i-1] + 1
实现代码
// 位运算int k = i;while(k!=0){int temp = k>>1;if(k!=temp<<1){res[i]++;}k = temp;}// 动态规划public int[] countBits(int n) {int[] res = new int[n+1];for (int i = 1; i <= n; i++) {res[i] = i%2 == 0 ? res [i/2] : res[i-1] + 1;}return res;}
时间及空间复杂度分析
两种思路时间复杂度均为一次遍历O(n),空间复杂度返回长度n的数组,空间复杂度O(n)
拓展思路
leetcode题解
值得一提的是,官方题解中提出了几种按位与(&)运算的用法,值得了解。
- 对任意数x 使 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「一比特数」。
- 若 y & (y−1)=0 则表示 y为2的幂
评论区题解
提到直接取最低位的方法,lowbit运算 y = x& -x,结果y就为最低位的值
