问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
如何去解决这个问题呢,很显然方法有很多,即使是最简单的暴力,遍历统计也是可以实现的,或者哈希 但是我们这里先使用一下异或。 什么是异或呢。 异或有这些特点 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,否则为0。
- 或运算(|) :对两个二进制数的每一位进行或运算,如果两个相应的二进制位中有1,则该位的结果值为1,否则为0。
- 异或运算(^) :对两个二进制数的每一位进行异或运算,如果两个相应的二进制位相同,则该位的结果值为0,不同则为1。
- 取反运算(~) :对一个二进制数的每一位进行取反运算,即1变为0,0变为1。
- 左移运算(<<) :将一个二进制数的所有位向左移动指定的位数,右边缺失的位用0补齐。左移运算相当于乘以2的指定次方。
- 右移运算(>>) :将一个二进制数的所有位向右移动指定的位数,对于无符号数,左边缺失的位用0补齐;对于有符号数,如果符号位为0(正数),左边缺失的位也用0补齐,如果符号位为1(负数),则取决于计算机系统的实现,有的系统用0补齐,有的系统用1补齐(算术右移)。右移运算相当于除以2的指定次方。
位运算其实就是将数字转为二进制计算,那么各二进制位出现的次数都是三的倍数,所以统计出这个余数,就是我们的单独数字了
余数可能为0,1,2
就像三进制一样逢三进一,但是二进制没有2,我们用两个二进制表现,即,00,01,10.
如果不为零我们就要一直继续,在二进制里就是0=0,1=~1=0.
这样问题就解决了。
对于编程,也许解决的方式很简单,如果硬要暴力的话,(摸鼻子)毕竟我们是python,排序后每三个一查找,也是可以解决的,但正是有些精彩的解法让我们想要学习,即使题的简单