本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目描述:
二、思路分析:
冲鸭,连续打卡第十天,缸子就要到手啦。今天给大家分享的是一道medium题目,跟我们昨天分享的题目有关系。昨天的是求两个整数的汉明距离。今天是给出一个数组,求出数组中任意两个数之间的汉明距离的总和。
暴力搞
说实话,看到题目的数据量 10^4, 就想直接暴力搞一下。挨个两两遍历所有数,分别调用昨天的题目里的求汉明距离的方法即可。果然,不出意外的超时了。
按位遍历求和
其实我们求汉明距离的时候就是按位求不同的数目。我们可以直接遍历32个bit位,对于每一位,我们求所有数字的对应位中数字1 和 数字0 的数目,那么对于这一位的汉明距离和就是 数字1出现的数目和数字0出现的数量相乘。然后遍历完所有位累加即为结果。
三、AC 代码:
//超时
class Solution {
/**
* @param Integer[] $nums
* @return Integer
*/
function totalHammingDistance($nums) {
$ret = 0;
$len_n = count($nums);
for ($i = 0; $i < $len_n; $i++) {
for ($j = $i + 1; $j < $len_n; $j++) {
$ret += $this->hammingDistance($nums[$i], $nums[$j]);
}
}
return $ret;
}
protected function hammingDistance($x, $y)
{
$ret = 0;
$temp = $x ^ $y;
while ($temp) {
$temp = $temp & ($temp - 1);
$ret++;
//echo $temp;
}
return $ret;
}
}
//按位遍历
function totalHammingDistance($nums) {
$ret = 0;
$len_n = count($nums);
for ($i = 0; $i < 32; $i++) {
$zero = $one = 0;
for ($j = 0; $j < $len_n; $j++) {
if (($nums[$j] >> $i) & 1) {
$one++;
} else {
$zero++;
}
}
$ret += $zero * $one;
}
return $ret;
}
四、总结:
位运算,一般的暴力思路无法通过时,可以考虑按位遍历,一般整数32位,往往有奇效。类似的还有题目中说只有小写英文字母时,往往可以搞个26长度的数组。