Python面试宝典第24题:找不同的数

题目1

        在一个整型数组中,数字都是两两相同,只有一个不同,请编写代码,最快找出这个不同的数字。

异或法

        初看题目,觉得不难。遍历数组两遍,不就能找到那个不同的数字了吗?但题目中提到“最快”,当前遍历数组的方法显然并不高效。那么,有更快的方法找出这个不同的数字吗?

        我们可以思考一下异或运算的特点:两个相同的数异或为0,两个不同的数异或不为0,与0异或值不变。另外,异或还满足交换律,a^b^c与a^c^b的值相等。根据这个特点,我们将数组中的所有数字异或一遍:两两相同的数异或为0,0与不同的那个数异或,最终结果即为要找的那个数。根据这个思路,我们给出了下面的示例代码。

def find_single_unique_number(nums):
    single_number = 0
    for num in nums:
        single_number ^= num
    return single_number

print(find_single_unique_number([26, 15, 32, 88, 26, 32, 88]))
print(find_single_unique_number([100, 24, 36, 87, 87, 56, 36, 100, 24]))

题目2

        在一个整型数组中,数字都是两两相同,只有两个不同,请编写代码,最快找出这两个不同的数字。

分治法

        与第一道题不同,本题数组中有两个不同的数字了,怎么办呢?我们可以猜测一下出题者的出题意图,先出了简单一点的第一题,然后出了难一点的第二题,这是否是在暗示我们:第二题需要根据第一题的解题思路,再深入思考呢?

        实际上,有了第一题的结论,我们可以考虑能否将这个数组划分成两个数组,使每个数组中各包含一个只出现了一次的数字。由于有两个数字只出现了一次,故将所有数异或后,结果肯定不为0,其二进制表示中至少有一位为1。可以依据这一位是否相同,将原数组划分成两个数组,从而直接套用第一题的结论来解题。

        下面,我们给出了第二道题的示例代码。

def find_two_unique_numbers(nums):
    xor_result = 0
    for num in nums:
        xor_result ^= num
    
    # 找到最右边的1的位置,即为两个不同数字在二进制上不同的位
    rightmost_bit = 1
    while (xor_result & rightmost_bit) == 0:
        rightmost_bit <<= 1
    
    # 根据这个位将数组分为两个子集
    num1, num2 = 0, 0
    for num in nums:
        if (num & rightmost_bit) != 0:
            num1 ^= num
        else:
            num2 ^= num
    
    return [num1, num2]

print(find_two_unique_numbers([26, 15, 32, 88, 26, 100, 32, 88]))
print(find_two_unique_numbers([100, 24, 36, 87, 87, 63, 56, 36, 100, 24]))

总结

        通过这道题,我们学习了异或运算的特点,并利用该特点,找出了数组中不同的数。在第二道题中,我们采用了“分而治之”的思想,将原数组从逻辑上划分成了两个数组,从而顺利找到了两个不同的数。

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

希望_睿智

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

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

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

打赏作者

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

抵扣说明:

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

余额充值