汉明距离总和–java–位运算
这道题很容易想到暴力解法,但就算在暴力解法的前提下加上备忘录,还是会超时,所以应该需要更高效的算法来解决。
其实通过观察规律很容易可以得到结论:
例如:[4,14,2]
二进制形式为:
0 1 0 0
1 1 1 0
0 0 1 0
最终结果为:
第一列上0的个数乘第一列上1的个数 + 第二列上0的个数乘第二列上1的个数 + 第三列上0的个数乘第三列上1的个数 + 第四列上0的个数乘第四列上1的个数
所以最终结果为 2 * 1 + 1 * 2 + 1 * 2 + 3 * 0 = 6
代码如下:
class Solution {
// 方法一:暴力法
// 使用缓存避免一些重复计算
// private Map<Integer,Integer> map = new HashMap<>();
// public int totalHammingDistance(int[] nums) {
// int ans = 0;
// for( int i = 0; i < nums.length - 1; ++i ){
// for( int j = i + 1; j < nums.length; ++j ){
// ans += hammingDistance(nums[i],nums[j]);
// }
// }
// return ans;
// }
// public int hammingDistance(int a, int b) {
// int res = a ^ b;
// // 如果缓存中存在已经计算过汉明距离的数,则直接返回
// if( map.containsKey(res) ){
// return map.get(res);
// }
// int cnt = 0;
// while( res > 0 ){
// if( res % 2 == 1 ){
// ++cnt;
// }
// res >>= 1;
// }
// // 注意,这里不可以用res做key了,因为res的值已经发生了改变
// map.put(a ^ b,cnt);
// return cnt;
// }
// 方法二:找规律,将整个数组写成二进制的形式,可以发现结果就是每位所有的一的个数乘零的个数,再相加
public int totalHammingDistance(int[] nums) {
Arrays.sort(nums);
int max = nums[nums.length - 1];
int ans = 0;
while( max > 0 ){
int oneCnt = 0;
int zeroCnt = 0;
for( int i = 0; i < nums.length; ++i ){
if( nums[i] % 2 != 0 ){
++oneCnt;
}else {
++zeroCnt;
}
nums[i] >>= 1;
}
ans += oneCnt * zeroCnt;
max >>= 1;
}
return ans;
}
}