|
1 | 1 | # 338. Counting Bits
|
2 | 2 |
|
3 |
| -# Description |
| 3 | +## #1 暴力搜索[AC] |
4 | 4 |
|
5 |
| -Given a non negative integer number **num**. For every numbers **i** in the range **0 ≤ i ≤ num** calculate the number of 1's in their binary representation and return them as an array. |
| 5 | +### 思路 |
6 | 6 |
|
7 |
| -**Example:** |
8 |
| -For `num = 5` you should return `[0,1,1,2,1,2]`. |
| 7 | +我们需要算法`0<=i<=num`这个范围内,每个数中有几个1,最直接的想法当然是遍历这个范围内的所有数值,然后求解这个数值有几个1。 |
9 | 8 |
|
10 |
| -**Follow up:** |
| 9 | +### 算法 |
11 | 10 |
|
12 |
| -- It is very easy to come up with a solution with run time **O(n\*sizeof(integer))**. But can you do it in linear time **O(n)** /possibly in a single pass? |
13 |
| -- Space complexity should be **O(n)**. |
14 |
| -- Can you do it like a boss? Do it without using any builtin function like **__builtin_popcount** in c++ or in any other language. |
| 11 | +```java |
| 12 | +class Solution { |
| 13 | + public int[] countBits(int num) { |
| 14 | + int[] res = new int[num+1]; |
| 15 | + for(int i=0; i<res.length; i++){ |
| 16 | + int count = 0; |
| 17 | + int val = i; |
| 18 | + for(int j=0; j<32; j++){ |
| 19 | + if((val & 1) == 1) |
| 20 | + count++; |
| 21 | + val >>= 1; |
| 22 | + } |
| 23 | + res[i] = count; |
| 24 | + } |
| 25 | + return res; |
| 26 | + } |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +此外,我们还可以通过`x&=(x-1)`消除最后一个1的方式来统计`x`中到底有多少个1。 |
| 31 | + |
| 32 | +```java |
| 33 | + private int popcount(int x) { |
| 34 | + int count; |
| 35 | + for (count = 0; x != 0; ++count) |
| 36 | + x &= x - 1; //zeroing out the least significant nonzero bit |
| 37 | + return count; |
| 38 | + } |
| 39 | +``` |
| 40 | + |
| 41 | +### 复杂性分析 |
| 42 | + |
| 43 | +- 时间复杂性:$O(n*sizeof(interger))$ |
| 44 | +- 空间复杂性:$O(n)$ |
| 45 | + |
| 46 | +## #2 动态规划(高位添1)[AC] |
| 47 | + |
| 48 | +### 思路 |
| 49 | + |
| 50 | +通过观察二进制数的特点,我们发现可以在某个数a的二进制前面添1来得到更大的数b,而b中1的数量比a多1。比如: |
15 | 51 |
|
16 |
| -# Solution |
| 52 | +$$\begin{align} (0) &= (0)_2 \\ (1) &= (1)_2 \\ (2) &= (10)_2 \\ (3) &= (11)_2 \\ \end{align}$$ |
17 | 53 |
|
18 |
| -这道题目,是关于bit操作的题目,bit操作,还不是很熟悉,这里要求出递增数值的bit表示中,1的个数。把答案抄上了,感觉还是迷迷糊糊,找个时间好好总结一下。 |
| 54 | +我们发现,在数值$0$的二进制前面加1,会得到$3$,而3二进制表示法中1的个数比0的二进制表示法中1的个数多1。 |
| 55 | + |
| 56 | +我们记$P(x)$表示x的二进制表示法中1的个数,于是,我们得到如下的表示式子: |
| 57 | + |
| 58 | +$$P(x+b) = P(x) + 1, b=2^m > x$$ |
| 59 | + |
| 60 | +基于这个表达式,我们可以设计出动态规划的算法来求解。 |
| 61 | + |
| 62 | +### 算法 |
19 | 63 |
|
20 | 64 | ```java
|
21 |
| -class Solution { |
| 65 | +public class Solution { |
22 | 66 | public int[] countBits(int num) {
|
23 |
| - int[] ret = new int[num+1]; |
24 |
| - ret[0] = 0; |
25 |
| - int pow = 1; |
26 |
| - for(int i=1, t=0; i<=num; i++, t++){ |
27 |
| - if(i == pow){ |
28 |
| - pow *= 2; |
29 |
| - t = 0; |
| 67 | + int[] ans = new int[num + 1]; |
| 68 | + int i = 0, b = 1; |
| 69 | + // [0, b) is calculated |
| 70 | + while (b <= num) { |
| 71 | + // generate [b, 2b) or [b, num) from [0, b) |
| 72 | + while(i < b && i + b <= num){ |
| 73 | + ans[i + b] = ans[i] + 1; |
| 74 | + ++i; |
30 | 75 | }
|
31 |
| - ret[i] = ret[t] + 1; |
| 76 | + i = 0; // reset i |
| 77 | + b <<= 1; // b = 2b |
32 | 78 | }
|
33 |
| - return ret; |
| 79 | + return ans; |
34 | 80 | }
|
35 | 81 | }
|
36 | 82 | ```
|
37 | 83 |
|
| 84 | +### 复杂度分析: |
| 85 | + |
| 86 | +- 时间复杂度:$O(n)$ |
| 87 | +- 空间复杂度:$O(n)$ |
| 88 | + |
| 89 | +## #3 动态规划(最低位消1)[AC] |
| 90 | + |
| 91 | +### 思路 |
| 92 | + |
| 93 | +想法和上面的类似,只是我们利用了`x&(x-1)`会去掉最后一个1的技巧,来重写我们的转移方程: |
| 94 | + |
| 95 | +$$P(x+b) = P(x \& (x-1)) + 1$$ |
| 96 | + |
| 97 | +### 算法 |
| 98 | + |
| 99 | +```java |
| 100 | +public class Solution { |
| 101 | + public int[] countBits(int num) { |
| 102 | + int[] ans = new int[num + 1]; |
| 103 | + for (int i = 1; i <= num; ++i) |
| 104 | + ans[i] = ans[i & (i - 1)] + 1; |
| 105 | + return ans; |
| 106 | + } |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +### 复杂度分析: |
| 111 | + |
| 112 | +- 时间复杂度:$O(n)$ |
| 113 | +- 空间复杂度:$O(n)$ |
| 114 | + |
0 commit comments