【LeetCode】汉明距离总和Java题解|Java刷题打卡

203 阅读1分钟

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

题目描述

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

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

示例:

输入: 4, 14, 2

输出: 6

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/total-hamming-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

  • 今天这个题目是汉明距离的升级版,分析题目之后,可以分为两个子问题解决。
  • 子问题一是求数组长度为2的子集。
  • 子问题二是求子集的汉明距离。可以得出如下代码:

代码

public int totalHammingDistance(int[] nums) {
        int ans = 0;
        List<List<Integer>> subLists = subList(nums);
        for (List<Integer> item : subLists) {
            if (item.size() == 2) {
                ans += Integer.bitCount(item.get(0) ^ item.get(1));
            }
        }
        return ans;
    }

    public List<List<Integer>> subList(int[] nums) {
        List<List<Integer>> subLists = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        dfs(nums, 0, temp, subLists);
        return subLists;
    }

    private void dfs(int[] nums, int level, List<Integer> temp, List<List<Integer>> subLists) {
        if (level == nums.length) {
            subLists.add(new ArrayList<>(temp));
            return;
        }
        dfs(nums, level + 1, temp, subLists);
        temp.add(nums[level]);
        dfs(nums, level + 1, temp, subLists);
        temp.remove(temp.size() - 1);
    }
  • 上述代码首先求解了 nums 的所有子集,然后取出长度为 2 的子集求汉明距离之和。提交超时没有通过!
  • 在提交超时之后,结合题目,再次分析,发现无需枚举所有子集,只需要找到长度为 2 的子集即可。优化代码如下:
    public int totalHammingDistance1(int[] nums) {
        int ans = 0;
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                ans += Integer.bitCount(nums[i] ^ nums[j]);
            }
        }
        return ans;
    }

提交测试:

image.png

  • 这个代码AC了,但是时间复杂度是 O (n * n), 还有优化的空间。
  • 参考官方题解,得到如下代码。这种解法的核心思想是分别统计位1 和 位0 的个数,然后统计整体汉明距离。这种思路不是很容易想到。又学习了一种新的思想!
    public int totalHammingDistance(int[] nums) {
        int n = nums.length;
        int ans = 0;
        for (int i = 0; i < 30; i++) {
            int oneCount = 0;
            for (int num : nums) {
                if (((num >> i) & 1) == 1) {
                    oneCount++;
                }
            }
            ans += oneCount * (n - oneCount);
        }
        return ans;
    }

提交测试:

image.png

总结

  • 这个题目今天提交了多次,才通过,在思路上走了一些弯路。纸上得来终觉浅,绝知此事要躬行!还是要认真分析题目,整理思路,不断提升!
  • 坚持每日一题,加油!