【位运算】力扣136: 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例:

输入: [4,1,2,1,2]
输出: 4

方法1:暴力解法
设置两个指针,前指针一格一格后移遍历。
在前指针固定的情况下,后指针遍历前指针后的所有数字。

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            flag = 0
            for j in range(n):
                if nums[i] == nums[j] and i != j:
                    flag += 1
                    break
            if flag == 0:
                res = nums[i]
                break
        return res

超出时间限制
时间复杂度:二重循环,为O(N^2)
空间复杂度:除了两个指针外没有额外空间消耗,O(1)

方法2:哈希表
利用hashtable记录已经出现过的数字,避免重复遍历

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        ht = [0] * 100000 # 注意长度要大于10000
        n = len(nums)
        for i in range(n):
            ht[nums[i]] += 1
        for i in range(n):
            if ht[nums[i]] == 1:
                return nums[i]

时间复杂度:两次遍历,O(N)
空间复杂度:一个哈希表,O(N)

方法3:快排
如何再继续降低复杂度呢?这样就想到了排序:先用快排将数组排序,找到与前后都不一样的数字即可。
一种暴力解法

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        nums.sort()
        n = len(nums)
        for i in range(1, n - 1):
            if nums[i] != nums[i - 1] and nums[i] != nums[i + 1]:
                return nums[i]
        if n > 1:
            if nums[0] != nums[1]:
                return nums[0]
            if nums[n - 1] != nums[n - 2]:
                return nums[n - 1]
        else:
            return nums[0]

时间复杂度:一次快排一次遍历,O(NlogN)
空间复杂度:O(N)

方法4:异或
题目说:除了某个元素只出现一次以外,其余每个元素均出现两次。这是个突破口 —— 异或运算!

  1. 异或运算具有交换律和结合律
  2. 一个数【异或】它本身为 0,一个数【异或】0 还是它本身,即 x ^ x = 0 和 x ^ 0 = x
    ∴ 把所有数字都异或起来就是所要的答案。出现两次的所有数字按位异或的结果是 0,0 与出现一次的数字异或可以得到这个数字本身。
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        for i in range(1, len(nums)):
            nums[0] ^= nums[i]
        return nums[0]

一行代码

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        return reduce(lambda x,y:x^y, nums)

作者:Jam007
链接:https://leetcode.cn/problems/single-number/solution/by-jam007-i6j8/

时间复杂度:一遍遍历,O(N)
空间复杂度:无任何额外空间,O(1)

方法5 取巧
只有一个数出现一次,每个不同的数总和 * 2 作差

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        return 2*sum(set(nums))-sum(nums) # set(nums)去掉数组中的重复数字

作者:Jam007
链接:https://leetcode.cn/problems/single-number/solution/by-jam007-i6j8/
posted @ 2022-05-12 12:07  Vonos  阅读(62)  评论(0)    收藏  举报