只出现一次的数字
问题
ps:部分代码参考leetcode和剑指offer。另外,三道题目都可以通过HashMap和Hashset做
1、只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
def singleNumber(nums): """ 异或:相同为0,不同为1 """ r = 0 for i in nums: r ^= i return r
2、只出现一次的数字 II
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
# 方法一 def find_num_appear_once(arr): """ 出现3次就不能再用异或的方法了,因为三个相同的数异或还是得到本身。但是还是可以采用位运算的思想,因为出现三次的数字每个位(0或者1)也是出现三次,因此可以每一位的和能够被3整除(对3取余为0)。所以如果把每个数的二进制表示的每一位加起来,对于每一位的和,如果能被3整除,那对应那个只出现一次的数字的那一位就是0,否则对应的那一位是1。 我们需要用一个数组bitSum保存每一位的和,具体来讲实现过程是,先初始化为0,然后对于每个数字,遍历它二进制表示的每一位,如果这一位是1,bitSum对应的那一位就加1。 """ if not arr: return max_length = max([len(bin(x)) for x in arr]) bits_count = [0] * max_length for x in arr: bit_mask = 1 # 对于每个数都从最低位开始判断 for bit_index in range(max_length - 1, -1, -1): if x & bit_mask != 0: bits_count[bit_index] += 1 bit_mask = bit_mask << 1 result = 0 for count in bits_count: result = result << 1 # 先把当前结果左移到高位 result += count % 3 # 然后把当前位应该为0还是1填上去 return result # 方法二 def find_num_appear_once_2(nums): seen_once = seen_twice = 0 for num in nums: # first appearance: # add num to seen_once # don't add to seen_twice because of presence in seen_once # second appearance: # remove num from seen_once # add num to seen_twice # third appearance: # don't add to seen_once because of presence in seen_twice # remove num from seen_twice seen_once = ~seen_twice & (seen_once ^ num) seen_twice = ~seen_once & (seen_twice ^ num) return seen_once # 方法三,对方法二的解释 def find_num_appear_once_2_explain(nums): one = 0 two = 0 for num in nums: # two的相应的位等于1,表示该位出现2次 two |= (one & num) # one的相应的位等于1,表示该位出现1次 one ^= num # three的相应的位等于1,表示该位出现3次 three = (one & two) # 如果相应的位出现3次,则该位重置为0 two &= ~three one &= ~three return one
3、只出现一次的数字 III
给定一个整数数组 nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
""" 从头到尾一次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数组的异或结果。因为其他数字都出现了两次,在异或中全部抵消了。 由于两个数字肯定不一样,那么异或的结果肯定不为0,也就是说这个结果数组的二进制表示至少有一个位为1。 我们在结果数组中找到第一个为1的位的位置,记为第n位。 现在我们以第n位是不是1为标准把元数组中的数字分成两个子数组,第一个子数组中每个数字的第n位都是1,而第二个子数组中每个数字的第n位都是0。 """ def find_nums_appear_once(arr): if not arr or len(arr)<2: return [] res = 0 for i in arr: res = res^i index = find_first_bit_is_1(res) num1 = 0 num2 = 0 for i in arr: if is_bit_1(i,index): num1 = num1^i else: num2 = num2^i return num1,num2 def find_first_bit_is_1(num): """ 找到num的二进制位中最右边是1的位置 """ index_of_bit = 0 while num != 0 and num & 1 == 0: num = num >> 1 index_of_bit += 1 return index_of_bit def is_bit_1(num,index): """ 判断第index位是不是1 """ num = num>>index return num&1 if __name__ == "__main__": print(find_nums_appear_once([-8, -4, 3, 6, 3, -8, 5, 5]))