(python)小菜狗算法日记(数组系列)_leetcode 面试题56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

限制:

2 <= nums <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof
暴力hash表:试了在写hash表时,把键为2的键值删掉,不晓得为啥效率还低了,就没删

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        num_dict = {}
        for num in nums:
            if num not in num_dict.keys():
                num_dict[num]=1
            else:
                num_dict[num]+=1
        res = []
        for key,val in num_dict.items():
            if val==1:
                res.append(key)
        return res

另一个异或的方法因为我不熟悉^,&,<<的运算看了半天才看懂,总体来说就是分三步走:1:把数组的所有数异或起来,因为两个相同的数异或起来等于0,比如4^4=0,0异或任何数就等于那个数。比如0^1=1。因为相同的数都抵消了,剩下的就是只出现过一次的两个数的异或值,比如[4,1,4,6],就剩下1^6=7.

2.选取一个两个数不相同的位用来分组。比如1是001,6是110,它两个每一位都不同,随便取哪位都行,这里取低位1。001和101(5)的话后两位都相同,从右往左数第三位不同,所以用这一位为1的数也就是100去做分组。

3.用步骤二取到的位做分组。遍历数组与步骤二取到的位做&运算。相同的数肯定会被分到同一组,所以不管分到哪一组都行,反正都会抵消。剩下两个只出现一次的数,因为在取到的位上这两个数不同,则这两个数与这个位结果是不同的,因此可以分组。

比如001&1=1,110&1=0不同。 001&100=0,101&100=1不同。

class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        # ret = functools.reduce(lambda x, y: x ^ y, nums)
        ret=0
        for num in nums:
            ret^=num
        div = 1
        while div & ret == 0:
            div <<= 1
        a, b = 0, 0
        for n in nums:
            if n & div:
                a ^= n
            else:
                b ^= n
        return [a, b]

代码来源:作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-by-leetcode/

有一个需要注意的地方就是div&ret==0这里不能用div&ret!=1,因为这里div左移后结果可能为10,100这些不等于1且可以退出循环的数。同理下面n&div也是,应该写成if n & div: 或if n & div==0:,不能写成if n & div==1:

这个reduce函数以前没见过,用法:reduce(function, sequence[, initial]) -> value

对sequence连续使用function, 如果不给出initial, 则第一次调用传递sequence的两个元素, 以后把前一次调用的结果和sequence的下一个元素传递给function. 如果给出initial, 则第一次传递initial和sequence的第一个元素给function.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值