题目1:一个正整数数组,有2个数只出现了一次,其他的数都出现了2次,求出这2个只出现了一次的数。要求算法复杂度为O(n),空间复杂度为O(1)
思路:所有数相异或,出现2次的数消掉了,剩下的是出现1次的2个数相异或的结果,结果的为1的位表示这2个数的差异位。
比如list_t=[1,2,3,8,4,4,3,1,5,5],所有数相与的结果为‘0b1010’,2与8在第二位和第4位是不相同的。
将数组分成2部分,所有第4位为1的为一组,为0的在另一组。那么那2个只出现一次的数必然分开在了2边,而且相同的2个数也必然在同一边。
那么每一边都只会出现一个单独的数,对两边分别求异或,就可以得出单独的数。
#一个数组,有2个数只出现了一次,其他数都出现了2次,求出这2个数 import math def findone(list_t,first_num,second_num): r=list_t[0] for i in list_t[1:len(list_t)]: #这样求出了只出现一次的2个数之间的差异 r=r^i #接下来要找到这2个数其中一个差异位 str_r=bin(r)[2:len(bin(r))] #把r转换为二进制形式。bin()将十进制整数转换为二进制字符串,前面有0b. r=int(math.pow(2,len(str_r)-1)) m=0 #用于分成两类的指针 n=len(list_t)-1 while(m<n): #把数组中的数分成2类。一类是所有的数在位b上为1,另一类是不为1.这两个不同的数一定分开在这两边了 while(list_t[n]&r!=0): n=n-1 temp=list_t[n] #第一个b位为1的数,存储在temp中 while(m<n and list_t[m]&r==0): m=m+1 list_t[n]=list_t[m] #第一个b为不为1的数,移到前面,把temp中的数移到后面 list_t[m]=temp print m #m表示的是最后一个b位不为1的数 print list_t first=list_t[0] second=list_t[m+1] for i in list_t[1:m+1]: #两个相同的数一定会在同一边,只分别出现一次的数一定分开在了两边。对这两边分别相与,可以得出出现一次的数 first^=i for i in list_t[m+2:len(list_t)]: second^=i return first,second first_num=0 second_num=0 list_t=[1,2,3,8,4,4,3,1,5,5,8,7] first_num,second_num=findone(list_t,first_num,second_num) #注意python可以一次返回多个值,多次赋值。python中的引用概念不强 print "first_num:%d" %first_num print "second_num:%d" %second_num #for i in range(1,len(str_r)): #提取r的首位为1,其他为0。表示这两个数在某一个位b上不相同 #str_r[i]='0' #字符串不支持按位幅值 #r=int(str_r,2)
几个注意的python语法:
1.bin(x) 将整数转换为二进制字符串,前面有0b字符,要去掉
2.math.pow(x,y)求x的y次幂
3.for i in range(1,len(str_r)): 注意range的写法
4.字符串不支持按位幅值
5.注意python可以一次返回多个值,调用时可采用多参数赋值。python中的引用概念不强