持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
一、题目描述:
给你一个整数
n,对于0 <= i <= n中的每个i,计算其二进制表示中1的个数 ,返回一个长度为n + 1的数组ans作为答案。
示例 1:
输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:
输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
提示:
- 0 <= n <= 10^5
进阶:
- 很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?
- 你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )
二、思路分析:
在写代码之前,我们知道2的次幂都有0,1,2,4,8,16,32,64...,这些数的二进制数都只有1位! 因此,每次我们都利用不大于N的最大二进制1位数。
比如,我们要得到f(6),那么我们就需要f(6)=f(4)+f(2),这里4就是不大于6的最大二进制1位数。
因而,我们设定一个left和right,所有我们要的数都满足:left < N < right。
状态方程就是f(N) = f(left) + f(N - left)
三、AC 代码:
class Solution {
public int[] countBits(int num) {
int left = 1;
int right = 2;
if(num == 0){
return new int[]{0};
}
if(num == 1){
return new int[]{0,1};
}
int[] arr = new int[num+1];
arr[0] = 0;
arr[1] = 1;
for(int i=2;i<=num;i++){
if(i == right){
left *= 2;
right *= 2;
arr[i] = 1;
}
else{
arr[i] = arr[i-left] + arr[left];
}
}
return arr;
}
}
四、参考:
每日一题题解——无位运算的简单暴力解法 - 比特位计数 - 力扣(LeetCode)