题意:
给定一个非负整数n。从0到这个非负整数(共n+1个数),用一个数组返回这n+1个数的二进制表示的1的个数。 比如 3的二进制表示是11那么1的个数就是2.
分析:
列几个来看下: 0 、 1、 10、11、 100 、101、110、 111、 1000 => 0 1 1 2 1 2 2 3 1(2 2 3 2 3 3 4 1)
所以一般情况下, 每2的n++次方一个组,每组从1开始.
我们以1为分界线来研究:[0, 1, 1,2 , 1,2,2,3 , 1,2,2,3,2,3,3,4 ,1]
1 2 4 8 16
1是0+1 1,2 是前面的 0,1各自加1 1223是前面的0112各自加1 12232334是前面的01121223各自加1.
我们一般化的来考虑这个问题:比如第四组:12232334是前面所有各自加1. 我们要实现这个,需要描述两段区间:0到1前面那个,1到下一个1前面那个,这两段区间的长度相等。我们已经发现:下一个1是这一个1的角标乘2(除去第一个0)。所以充分的描述两段区间的同时遍历需要:第一段区间的开始位置,第二段区间的开始位置,和第一段(或第二段)区间的末尾或长度。
所以我们模拟出整个过程:第二个区间的指针p2一直往后遍历。而第一个区间的指针p1.每次走到区间末尾的时候,p1回到0.那么现在关键的问题就是怎么确定区间结尾:因为区间的结尾存在*2的关系,所以设置一个变量,作为区间结尾的标示。
public class Solution {
public int[] countBits(int num) {
int[] arr = new int[num+1];
arr[0] = 0;
int p1 = 0;
int p2 = 1;
int length = 1;
while(p2 <= num){
if(length == p1){ //每次第一段区间的指针走完第一段区间的长度,第一段区间的长度就倍增,且指针归零。
length *= 2;
p1 = 0;
}
arr[p2] = arr[p1] + 1;
p1++;
p2++;
}
return arr;
}
}