题目1
一个无序的数组里面有若干个正整数,范围是1-100,其中的99个整数都出现了偶数次,只有1个整数出现了奇数次,如何找到这个出现奇数次的整数?
思路
遍历整个数组,依次做异或运算。由于异或运算在进行运算时,相同为0,不同为1,因此所有出现偶次的整数都会相互抵消成为0,只有唯一出现奇数的整数会被留下。
如:
无序数组 | 3 | 1 | 3 | 2 | 4 | 1 | 4 | |
---|---|---|---|---|---|---|---|---|
异或运算 | 3 xor | 1 xor | 3 xor | 2 xor | 4xor | 1 xor | 4 xor | =2 |
假设数组长度为n,那么该解法的时间复杂度是O(n),空间复杂度为O(1)。
题目2
假设一个无序数组里有若干个正整数,范围是1-100,其中有98个整数出现了奇数次,其他的整数出现偶数次。如何找出这个2个出现奇次整数?
思路
把2个出现奇数次的整数命名为A和B,遍历整个数组,然后依次做异或运算,进行异或运算的最终结果,等于A和B进行异或运算的结果。在这个结果中,至少有一个二进制单位是1(如果是0,说明A和B相等。和题目不符)
如:无序数组{4,1,2,2,5,1,4,3},所有元素进行异或运算的结果是00000110B
无序数组 | 4 | 1 | 2 | 2 | 5 | 1 | 4 | 3 | |
---|---|---|---|---|---|---|---|---|---|
异或运算 | 1 xor | 1 xor | 2 xor | 2 xor | 5xor | 1 xor | 4 xor | 3 xor | 00000110B |
选定该结果中的值为1的某一位数字,如00000110B的倒数第2位是1,这说明对应的A和B的二进制的倒数第2位是不同的。其中必定有一个是0,有一个是1
根据这个结论可以把原来的数字按照二进制的倒数第2位的不同,分为两个部分,一部分的倒数第2位是0,另外一部分的倒数第2位是1。如:
5—>>二进制—>>101
3—>>二进制—>>011
倒数第2位,一个是0,一个是1
所以按照以上方法可将数组分为:
4,1,5,1,4和2,2,3两个部分。
接下来按照原来的异或运算,从每一部分找出唯一的奇数次即可。
假设数组长度为n,那么该解法的时间复杂度是O(n)。把数组分成两个部分,并不需要额外的存储空间,完全可以按照二进制位分组的同时来做异或运算,所以空间复杂度仍然是O(1)。
代码
def findLostNumber(array):
# 用于存储出现奇次的整数
resultList = [0 for i in range(2)]
# 第一次做整体异或运算
xorResult = 0;
for i in array:
xorResult^=i
if xorResult==0:
return None
# 确定2个整数的不同位,以此来做分组
separator = 1
while 0==(xorResult&separator):
separator<<=1;
# 第二次分组进行异或运算
for j in array:
if 0==(separator&j):
resultList[0]^=j
else:
resultList[1]^=j
return resultList
if __name__ == '__main__':
array = [4,1,2,2,5,1,4,3]
res = findLostNumber(array)
print(res)