题目
思路
最直接的算法是遍历所有的数字组合并将每组数字的汉明距离求和,然而其时间复杂度为 O ( n 2 ) O(n^2) O(n2),会超时。
我们考虑通过分治的方法来求解。首先考虑我们以及计算得到数组nums
前k
个数组成的区间[0, k-1]
的所有数字的汉明距离总和total(0, k - 1)
,那么[0,k]
中所有数字汉明距离的总和total(0, k)
就等于total(0, k-1)
加上nums[k]
同前k
个数字的汉明距离总和。
上述算法的时间复杂度仍然为
O
(
n
2
)
O(n^2)
O(n2),其同样遍历了所有数字组合,并没有达到优化的效果,不过可以看到如果求解nums[k]
和前k
个数的汉明距离之和可以
O
(
1
)
O(1)
O(1)完成,我们就可以得到一个
O
(
n
)
O(n)
O(n)的算法,然而,我们似乎并不能找到一种算法使得求解nums[k]
和前k
个数的汉明距离之和的时间复杂度为
O
(
1
)
O(1)
O(1)。
但是,如果我们仅考虑nums[k]
和前k
个数的某一个比特位(例如第n
比特)的汉明距离之和,则该操作可以在
O
(
1
)
O(1)
O(1)完成,因为我们可以分别记录前k
个数字中第n
比特为0和为1的数字数量为bit0
和bit1
,对于nums[k]
,如果其第n
比特为0
, 则在该比特位上,nums[k]
同前k
个数的汉明距离之和为bit1
(因为对于两个单个bit的数字,其汉明距离只能为0或者1,相同为0,否则为1);否则汉明距离之和为bit0
. 这样我们就实现了在
O
(
1
)
O(1)
O(1)的时间复杂度内求解nums[k]
和前k
个数在第n
个比特位上的汉明距离之和。对于32比特的整数,由于求解汉明距离时每个比特位都是独立的,不受其他比特位的值的影响,因此只需要对32个比特位均执行一次该操作即可求得最终的汉明距离和。
代码
class Solution {
public:
int totalHammingDistance(vector<int>& nums) {
int r=0;
for (int i=0; i<32; i++) {
// 当前比特位为0的数字数量
int bit0 = 0;
// 当前比特位为1的数字数量
int bit1 = 0;
for (int n : nums) {
if ( (n >> i) & 0x1) {
r += bit0;
bit1++;
} else {
r += bit1;
bit0++;
}
}
}
return r;
}
};