汉明距离总和

简介

力扣日常打卡时碰到了这样一个题,原本一个中级题目没什么好分享的,只是记录一下做题时的心理过程。

在力扣中,我属于慢刷派,每天都会去刷一下,通常得到第一个版本后,会再优化一下,在我感觉已经到我的极限时,再去看一下,性能最好的答案。

先说结论:如果你没有不断的尝试,你怎么知道早点放弃才是最快的解决方法,哈哈哈哈哈哈咯~

题目

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

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

示例:

输入: 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)

思路

  1. 首先你要先看题,大概捋一下逻辑
  2. 第一层 循环获取 参数数组nums中的每个元素index
  3. 内层轮询index后面的元素,得到需要比对元素
  4. 最里层比对两个元素的汉明距离并追加总和
  5. 最后在最外层返回总和

如此简单

搞起

class Solution {
	public int totalHammingDistance(int[] nums) {
		int count=0;
		for(int i=0;i<nums.length;i++){
			for(int j=i+1;j<nums.length;j++){
				count+=twoNumsHanming(nums[i],nums[j]);
			}
		}
		return count;
	}

	public int twoNumsHanming(int num1,int num2){
		int count=0;
		for(int i=31;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<nums.length;x++){
				if((nums[x] >>> i & 1)==1){
					num1count++;
				}
			}
			count+=num1count*(nums.length-num1count);
		}
		return count;
	}
}

看了这个答案后,心里相当不甘,但是没办法,是真的忘了或者不知道那个C*(N-C)的部分了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiao4-800k

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值