题目在这:https://leetcode-cn.com/problems/total-hamming-distance/
题目分析:
昨天是汉明距离。今天是昨天的升级版求好几个汉明距离的综合。
法一:
思路分析: 根据昨天的异或统计‘1’的方法。这道题很容易的就可以得到思路。直接暴力循环,
List = [4, 14, 2]
res = 0
for i in range(len(List)-1):
for j in range(i+1,len(List)):
temp = bin(List[i] ^ List[j])
for k in range(len(temp)):
if temp[k] == '1':
res += 1
print(res)
这段代码没什么好说的,两层循环遍历列表里的所有数,然后异或找其中的‘1’。最后统计就行了,对于这个算法不太理解的可以去看一下我昨天的文章,里面有对这个算法的详细介绍。
昨天的链接:
https://blog.csdn.net/qq_38737428/article/details/117373835?spm=1001.2014.3001.5501
但是这段代码leetcode上通过不了。超时了。。。。
害,一般暴力异或的情况都会超时。。。。。
法二:
思路分析: 我们将数组中的数变成二进制列出来,如图。
只看第一位的情况下:
从左往右看,取每个二进制的第一位数,即 :
4的二进制的第一位数0。
14的二进制的第一位数1.
2的二进制的第一位数0。
按照汉明距离的定义。
4和14的汉明距离为1。
4和2的汉明距离为1.
14和2汉明距离为0。 汉明距离总和:2
只看第二位的情况下:
4的二进制的第二位数1。
14的二进制的第二位数1.
2的二进制的第二位数0。
按照汉明距离的定义。
4和14的汉明距离为0。
4和2的汉明距离为1。
14和2汉明距离为1。 汉明距离总和:2
通过上面两个例子,其实不难发现,每一列的汉明距离总和为‘1’的个数乘以‘0’的个数。
这样我们只需要吧每一列的汉明距离加起来就行了。
核心算法代码:
for i in range(ln): # 遍历全部的列
zero = 0 # 每一列统计完了 计数器归零
one = 0
for j in range(len(nums)):
if list[j][i] == '0':
zero += 1
else:
one +=1
res += zero * one
print(res)
由于列表中的数转换成二进制可能位数不一样,所以需要统一位数,在位数短的前面补0。
比如:
1二进制为1
2二进制为10。
所以。。。
吧 1 前面补0 变为01 这样就可以和下面的10有相同位数了。方便使用上面的算法。
max_num = max(nums) # 找列表中最大的数
ln = len(bin(max_num)) # 把最大的数变为二进制并记录他的长度
我们用前面拿到的最长字符串长度,给短位的补0。
我们可以使用format函数进行进制转换和位数控制。给定的列表中最大的数字其转换为二进制之后一定是长度最长的。
for i in nums:
i = '{:0{}b}'.format(i,ln)
list.append(i)
PS:
8位二进制
‘{:08b}’.format(9)
‘00001001’
上面的b换成o就是换成八进制,换成x就是十六进制。
完整代码:
nums = [4, 14, 2]
res = 0
max_num = max(nums)
ln = len(bin(max_num))
list = []
for i in nums:
i = '{:0{}b}'.format(i,ln)
list.append(i)
print(list)
for i in range(ln):
zero = 0
one = 0
for j in range(len(nums)):
if list[j][i] == '0':
zero += 1
else:
one +=1
res += zero * one
print(res)