LeetCode-Python-477. 汉明距离总和 (位运算)

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

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

示例:

输入: 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)
链接:https://leetcode-cn.com/problems/total-hamming-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

第一种思路:

暴力解,

两个数一组计算汉明距离,再累加在一起。

时间复杂度:O(N^2 * log(K)), K = log2(10 ^9) 

空间复杂度:O(1)

第二种思路:

采取位运算的思想来计算答案,

比如对于样例输入= [4, 14, 2],

4 = 0100, 14 = 1110, 2 = 0010,

所以从右往左的:

第0位,有三个零,汉明距离为0

第1位,有两个一,一个零,2 * 1 = 2

第2位,有两个一,一个零,2 * 1 = 2

第3位,有一个一,两个零,2 * 1 = 2

最后累加在一起就是2 + 2 + 2 = 6。

算法本质就是找到每一位上,输入数组中二进制形式在这一位上的为1 的数的个数, 乘上 为0的数的个数,

最后累加在一起,即是答案。

时间复杂度:O(Nlog(K)),

空间复杂度:O(K)。

class Solution(object):
    def totalHammingDistance(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        max_l = len(bin(max(nums))[2:])
        
        dic = dict()
        for i in range(max_l + 1):
            dic[i] = [0, 0] # [0的个数,1的个数]
        
        for num in nums:
            s = bin(num)[2:]
            if len(s) < max_l: # 如果长度不够则需要补全
                s = (max_l - len(s)) * "0"+ s
                
            for i, digit in enumerate(s):
                dic[i][int(digit)] += 1
                
        res = 0
        for key, val in dic.items():
            cnt0, cnt1 = val[0], val[1]
            res += cnt0 * cnt1
            
        return res

第三种思路:

第二种思路的进阶版,其实没必要用哈希表存结果,

每一位算完了直接累加。

class Solution(object):
    def totalHammingDistance(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = 0
        mask = 1
        for i in range(32):
            cnt_one = 0
            for num in nums:
                cnt_one += 1 if num & mask else 0 
                
            res += cnt_one * (len(nums) - cnt_one)
            mask = mask << 1
        return res

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值