# LeetCode 477. Total Hamming Distance

@(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

注意:

  1. 每个整数值的范围为 0~10^9
  2. 数组的长度不会超过 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
};

你可能感兴趣的:(# LeetCode 477. Total Hamming Distance)