本文正在参加「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;
}
提交测试:
- 这个代码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;
}
提交测试:
总结
- 这个题目今天提交了多次,才通过,在思路上走了一些弯路。纸上得来终觉浅,绝知此事要躬行!还是要认真分析题目,整理思路,不断提升!
- 坚持每日一题,加油!