力扣日常打卡时碰到了这样一个题,原本一个中级题目没什么好分享的,只是记录一下做题时的心理过程。
在力扣中,我属于慢刷派,每天都会去刷一下,通常得到第一个版本后,会再优化一下,在我感觉已经到我的极限时,再去看一下,性能最好的答案。
先说结论:如果你没有不断的尝试,你怎么知道早点放弃才是最快的解决方法,哈哈哈哈哈哈咯~
两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。
计算一个数组中,任意两个数之间汉明距离的总和。
示例:
输入: 4, 14, 2
输出: 6
解释: 在二进制表示中,4表示为0100,14表示为1110,2表示为0010。(这样表示是为了体现后四位之间关系)
所以答案为:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
注意:
数组中元素的范围为从 0到 10^9。
数组的长度不超过 10^4。
来源:力扣(LeetCode)
如此简单
class Solution {
public int totalHammingDistance(int[] nums) {
int count=0;
for(int i=0;i=0;i--){
if((num1 >>> i & 1) != (num2 >>> i & 1)){
count++;
}
}
return count;
}
}
感觉性能不是很高,但毕竟只是开始。经过了测试用例,迫不及待想看看能跑第几名,直接提交答案。
最终:35 / 46 个通过测试用例
状态:超出时间限制
简单说就是由于耗时太多不接受此答案。
很明显,由于循环过多,导致时间超标了。在没有其他思路之前,只能在此基础上进行改进
首先就是要改进循环。但是无从下手,只能将hanming方法作为第一层循环,表面上看至少第一层只有32次循环。
但是答案依然超出时间限制。仔细想一下这种修改似乎并没有提升性能,因为循环总数是一样的。
终于在做了半个小时思想斗争后选择看答案,心里想毕竟程序没有错误只是时间超时了,看看答案能给出什么新花样。
逐位统计
在计算汉明距离时,我们考虑的是同一比特位上的值是否不同,而不同比特位之间是互不影响的。
对于数组 \textit{nums}nums 中的某个元素 \textit{val}val,若其二进制的第 ii 位为 11,我们只需统计 \textit{nums}nums 中有多少元素的第 ii 位为 00,即计算出了 \textit{val}val 与其他元素在第 ii 位上的汉明距离之和。
具体地,若长度为 nn 的数组 \textit{nums}nums 的所有元素二进制的第 ii 位共有 cc 个 11,n-cn−c 个 00,则些元素在二进制的第 ii 位上的汉明距离之和为
c\cdot(n-c)
c⋅(n−c)
我们可以从二进制的最低位到最高位,逐位统计汉明距离。将每一位上得到的汉明距离累加即为答案。
具体实现时,对于整数 \textit{val}val 二进制的第 ii 位,我们可以用代码 (val >> i) & 1 来取出其第 ii 位的值。此外,由于 109<2{30} ,我们可以直接从二进制的第 00 位枚举到第 2929 位。
修改代码
class Solution {
public int totalHammingDistance(int[] nums) {
int count=0;
for(int i=30;i>=0;i--){
int num1count=0;
for(int x=0;x>> i & 1)==1){
num1count++;
}
}
count+=num1count*(nums.length-num1count);
}
return count;
}
}
看了这个答案后,心里相当不甘,但是没办法,是真的忘了或者不知道那个C*(N-C)的部分了