找单独的数及升级版 | 豆包MarsCode AI刷题

45 阅读4分钟

问题描述

在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。

要求:

  1. 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
  2. 尽量减少额外空间的使用,以体现你的算法优化能力。

如何去解决这个问题呢,很显然方法有很多,即使是最简单的暴力,遍历统计也是可以实现的,或者哈希 但是我们这里先使用一下异或。 什么是异或呢。 异或有这些特点 a^a=0 a^b=1 a^0=a 异或运算满足交换律和结合律 如果你想交换两个值该如何呢,你可能说去建立一个临时的temp去储存

a=temp
a=b
b=temp

有了异或我们可以写 ``

1.  `a = a ^ b`
1.  `b = a ^ b`
1.  `a = a ^ b`

这样我们就不需要额外的临时变量。 由此我们可以轻而易举的得出这题的解法,两两异或必然为零,而零和单独的数异或又可以等于单独的数。

def solution(inp):  
    # 使用异或运算来找到只出现一次的元素  
    tmp = 0  
    for num in inp:  
        tmp ^= num  
    return tmp  
  

这让我们又想到了力扣中一个升级版

如果每个数出现三次,只有一个数字独特,且不开辟额外空间这还如何解决呢。 这里就是!!! 异或运算和与运算结合

与运算 x&0=0 x&1=x 很少用到的,其实也能直接背啦。

b2=0
b1=0
for x in nums:
    b1=(b1^x)&(~b2)
    b2=(b2^x)&(~b1)
return b1

如果你不甘心,那我只能说,你真是个有志气的少年。

  1. 与运算(&) :对两个二进制数的每一位进行与运算,如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。
  2. 或运算(|) :对两个二进制数的每一位进行或运算,如果两个相应的二进制位中有1,则该位的结果值为1,否则为0。
  3. 异或运算(^) :对两个二进制数的每一位进行异或运算,如果两个相应的二进制位相同,则该位的结果值为0,不同则为1。
  4. 取反运算(~) :对一个二进制数的每一位进行取反运算,即1变为0,0变为1。
  5. 左移运算(<<) :将一个二进制数的所有位向左移动指定的位数,右边缺失的位用0补齐。左移运算相当于乘以2的指定次方。
  6. 右移运算(>>) :将一个二进制数的所有位向右移动指定的位数,对于无符号数,左边缺失的位用0补齐;对于有符号数,如果符号位为0(正数),左边缺失的位也用0补齐,如果符号位为1(负数),则取决于计算机系统的实现,有的系统用0补齐,有的系统用1补齐(算术右移)。右移运算相当于除以2的指定次方。

位运算其实就是将数字转为二进制计算,那么各二进制位出现的次数都是三的倍数,所以统计出这个余数,就是我们的单独数字了

余数可能为0,1,2

就像三进制一样逢三进一,但是二进制没有2,我们用两个二进制表现,即,00,01,10.

如果不为零我们就要一直继续,在二进制里就是0=0,1=~1=0.

这样问题就解决了。

对于编程,也许解决的方式很简单,如果硬要暴力的话,(摸鼻子)毕竟我们是python,排序后每三个一查找,也是可以解决的,但正是有些精彩的解法让我们想要学习,即使题的简单