比特位计数(二十一)

一、题目描述

这是 LeetCode 上的第三百三十八题:比特位计数,难度为 简单

Tag:「位运算」

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

示例 1:

1
2
3
4
5
6
输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10

示例 2:

1
2
3
4
5
6
7
8
9
输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101

提示:

1、0 <= n <= 10^5

二、解题思路

最直观的做法是对从 0 到 n 的每个整数直接计算「一比特数」。每个 int 型的数都可以用 32 位二进制数表示,只要遍历其二进制表示的每一位即可得到 1 的数目。

利用 Brian Kernighan 算法,可以在一定程度上进一步提升计算速度。Brian Kernighan 算法的原理是:对于任意整数 x,令 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「一比特数」。

对于给定的 n,计算从 0 到 n 的每个整数的「一比特数」的时间都不会超过 O(logn),因此总时间复杂度为 O(nlogn)。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int[] countBits(int n) {
int[] bits = new int[n + 1];
for (int i = 0; i <= n; i++) {
bits[i] = countOnes(i);
}
return bits;
}

public int countOnes(int x) {
int ones = 0;
while (x > 0) {
x &= (x - 1);
ones++;
}
return ones;
}
}

复杂度分析:

1、时间复杂度:O(nlogn)。需要对从 0 到 n 的每个整数使用计算「一比特数」,对于每个整数计算「一比特数」的时间都不会超过 O(logn)。

2、空间复杂度:O(1)。除了返回的数组以外,空间复杂度为常数。

三、总结

本道算法题难度为简单,我们使用了 Brian Kernighan 算法(x &= (x - 1)),它会将我们二进制的最后一个 1 变成 0,因此我们使用一个变量记录这个操作的次数即可

好了,本篇文章到这里就结束了,感谢你的阅读🤝


比特位计数(二十一)
https://sweetying520.github.io/2022/08/25/A21-比特位计数(二十一)/
作者
sweetying
发布于
2022年8月25日
许可协议