2222222222222222222222222222222汉明距离总和 | Java刷题打卡

342 阅读1分钟

本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接

一、题目描述:

image.png

二、思路分析:

冲鸭,连续打卡第十天,缸子就要到手啦。今天给大家分享的是一道medium题目,跟我们昨天分享的题目有关系。昨天的是求两个整数的汉明距离。今天是给出一个数组,求出数组中任意两个数之间的汉明距离的总和。

暴力搞

说实话,看到题目的数据量 10^4, 就想直接暴力搞一下。挨个两两遍历所有数,分别调用昨天的题目里的求汉明距离的方法即可。果然,不出意外的超时了。 image.png

按位遍历求和

其实我们求汉明距离的时候就是按位求不同的数目。我们可以直接遍历32个bit位,对于每一位,我们求所有数字的对应位中数字1 和 数字0 的数目,那么对于这一位的汉明距离和就是 数字1出现的数目和数字0出现的数量相乘。然后遍历完所有位累加即为结果。

image.png

三、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长度的数组。