汉明距离总和

两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。

计算一个数组中,任意两个数之间汉明距离的总和。

示例:

输入: 4, 14, 2

输出: 6

解释: 在二进制表示中,4表示为0100,14表示为1110,2表示为0010。(这样表示是为了体现后四位之间关系)
所以答案为:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.

注意:

数组中元素的范围为从 0到 10^9。
数组的长度不超过 10^4。

初始的思路:

任意两个数之间汉明距离,直接使用两个循环,找出两个数,然后使用这两个数字进行异或计算。将得到的结果求二进制中存在1的数量,依次累加得到结果。

func totalHammingDistance(nums []int) int {
	if len(nums) <= 1 {
		return 0
	}
	result := 0
	for i:=0;i<len(nums);i++{
		for j := i+1;j<len(nums);j++{
			xorRes := nums[i] ^ nums[j]
			tmp := getBinaryOneCount(xorRes)
			result = result +  tmp
		}
	}
	return result
}

func getBinaryOneCount(num int)int{
	result := ""
	count := 0
	for num>1{
		a := num % 2
		if a == 0 {
			result = "0" + result
		}else if a == 1{
			count++
			result = "1" + result
		}
		num = num / 2
	}
	if num == 0 {
		result = "0" + result
	}else if num == 1{
		count++
		result = "1" + result
	}
	return count
}

结果:解题思路正确,但是会超时

基本思想

左移:向左移动n位,则增加2^n倍。在二进制中相当于向右部分添加n个零

9 << 2
9:1001
结果:36:100100

右移:向右移动n位,则降低2^n倍。在二进制中相当于向左部分减少n位

9 << 2
9:1001
结果:2:10

这道题想要减少运行时间,可以通过找规律解决

在计算汉明距离的时候,我们考虑的是同一位比特位上的值是否不同,而不同比特位之间是互不影响的。

对于数组nums中的某个元素val,若其二进制的第i位为1,我们只需要统计nums中有多少个元素的第i位为0,就可以计算出val与其他元素在第i位上的汉明距离之和。

若长度为n的数组的nums的所有元素的第i位的所有二进制的第i位共有c个1,n-c个0,则这些元素在二进制的第i位上的汉明距离之和为:c*(n-c)。然后将所有位的汉明距离累加,即可得到总体的汉明值。

所有位如何确定呢?因为题目给出元素的最大值不操作109,也就是说不大于230,所以最大的元素最多占用30位。

如何求每一位是否位1呢?计算公式位:(val >> i)&1,这里的i从0开始。

9:1001
9 >> 0 = 1001 & 1 = 1 第一位为1

9 >> 1 = 100 & 1 = 0  第二位为0

实现方式为:

func totalHammingDistance(nums []int)int{

	if len(nums) <= 1{
		return 0
	}
	// 因为10^9不大于2^30,因此可以假设有30位
	result := 0
	n := len(nums)
	for i:=0;i<30;i++{
		// 计算总共在第i位的有1的数量和0的数量,然后相互组合:n * (len(nums)-n)得到的结果为该位置的结果
		tmp := 0
		for _,val := range nums {   // 从0开始右移表示,从第一位开始移动。一开始不移动,然后移动1位整个二进制就会减少一位,也就相当于第二位
			tmp += val >> i & 1
		}
		// 所有位数不同组合的结果,总和
		result += tmp * (n-tmp)
	}
	return result
}
原文地址:https://www.cnblogs.com/MyUniverse/p/14823909.html