@(LeetCode)
问题描述
Hamming distance,汉明距离,用来表示两个等长字符串之间的差异性,即对应位置上字符不相等的个数。
两个整数之间的汉明距离定义为:以二进制表示整数,对应位上的值不相等的个数。
现给定一组数字,求出两两组合之后总的汉明距离。
举个栗子:
输入:4, 14, 2
输出:6
解释:
其二进制表示分别为:4 - 0100,14 - 1110,2 - 0010。
两两组合之后的距离之和为:
distance(4, 2) + distance(4, 14) + distance(14, 2) = 2 + 2 + 2 = 6
注意:
- 每个整数值的范围为
0~10^9
。 - 数组的长度不会超过
10^4
。
想看英文原文的戳这里。
解题思路
常规思路
最直接的想法,分别求出两两组合的汉明距离,然后相加求和即可。
而求两个整数之间的汉明距离,也比较简单。代码如下:
function hammingDistance(x, y) {
let dist = 0
let val = x ^ y
while (val > 0) {
if (val & 1) {
dist += 1
}
val >>= 1
}
return dist
}
提交之后,会得到 Time Limit Exceeded
的结果。
但是这个结果,并不意外,因为题目给定了一些限制条件。
- 整数的范围,
0 ~ 10^9
,最大数为30
位二进制,在计算汉明距离会对每位进行判断,那么最大次数为30
次。 - 数组最大长度为
10^4
,两两组合为n * (n - 1) / 2
,粗略估算一下,上亿级别。两者操作相乘,十亿级别, 灰常大的计算量了。
所以,需要另辟蹊径。
正确解法
思路
由于只需要求出对应二进制位上不同的个数,那么换个思路,可以转换为求对应位上的一组二进制,其两两组合不同的个数之和。
比如一组二进制位如下:
0
1
1
其两两组合为 0-1, 0-1, 1-1
,由于 1-1
是相等的,所以个数为 2
。
再举个栗子:
0
1
0
1
其两两组合为 0-1, 0-0, 0-1, 1-0, 1-1, 0-1
,去除相同的组合,个数为 4
。
从这两个栗子很好推断出计算公式:不同个数 = 0 的个数 * 1 的个数
。
那么,进一步,只需要求出一组二进制位中 1
的个数即可。
栗子
拿上述例子举例,其计算过程如下:
0100
1110
0010
从右往左开始:
- 第
0
列,都为0
, 那么不同的个数为0
。 - 第
1
列,个数为1 * 2 = 2
。 - 第
2
列,个数为1 * 2 = 2
。 - 第
3
列,个数为2 * 1 = 2
。
所以,总数为 2 + 2 + 2 = 6
。
我们可以大致估算一下处理次数:10^4 * 30
,十万级别,相比第一种解法好很多。
代码
js
代码如下:
// 54.05%
var totalHammingDistance2 = function(nums) {
let totalDist = 0
// 10^9,二进制位数最大为 30
let len = 30
let j = 0
// 取出 num 的每一位
let mask = 1
while (j < len) {
let count = 0
let i = 0
while (i < nums.length) {
// 计算 1 的个数
if (nums[i] & mask) {
count += 1
}
i += 1
}
if (count > 0) {
// 0 的个数与 1 的个数相乘,即为不同总数
totalDist += count * (nums.length - count)
}
j += 1
mask <<= 1
}
return totalDist
};