题目描述
两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。
计算一个数组中,任意两个数之间汉明距离的总和。
示例:
输入: 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。
思路
当然一开始想到的是将任意两个元素所有位比较一遍,得到汉明距离,然后再将这些距离都加起来。但是稍微学过一点数据结构和算法的都能想到这样做会有大量的重复比较,举个例子,a、b、c三个数,假设a最低位为1,b为0,c为1,在a与b、a与c比较完最低位之后,b与c没有就没有必要再比较最低位了(因为a与c相同,a与b不同,那么c与b一定不同)。
所以换个思路,对于二进制数来说每一位不是0就是1,如果在总数为n个的数组中有a个元素的第i位为1,则第i位为0的有n-i个元素,按照排列组合的知识,就第i位来说,从这a个元素里任取一个,它与这n-a个元素中的任一个元素距离都是1,而这样的组合一共有a*(n-a)个。将i从第0位到最高位时的a*(n-a)加起来就是总的距离。
还有一个问题是如何判断已经移动到最高位了(这里最高位不是int的位数,而是使得数组中所有元素都为0时,所需要向右移动的最小位数),每次将各个元素除以2,相当于右移,移动到元素值全部为0时,就结束了
class Solution {
public:
int totalHammingDistance(vector<int>& nums) {
int nonzeros=1;
int sum=0;
while(nonzeros){
nonzeros=0; //判断元素是不是全都为0了
int num_of_one=0;
for (int i = 0; i < nums.size(); ++i) {
int temp=nums[i]%2; //取最低位
nums[i]/=2; //右移一位
if(nums[i])nonzeros++;
if(temp)num_of_one++;
}
sum+=num_of_one*(nums.size()-num_of_one);
}
return sum;
}
};
测试结果
不是太好,中规中矩吧,应该还能再抢救(优化)一下