这是刷LeetCode的第五天,原题地址。
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例一
输入: [2,2,1]
输出: 1
示例二
输入: [4,1,2,1,2]
输出: 4
解题思路
第一种方法
通过将数组排序,然后遍历数组,每两个对比,如果相同,则进入下一对;如果不相同则返回该对的第一个数。
但这个方法我没有找到如何处理数字出现在最后一对中的情况,即被单着的时候。脑子有点乱,没想清楚数组下标的情况。
第二种方法
从官方题解看到一个解法,用位运算。此题可以采用异或运算,即^。
- 任何数和 0 做异或运算,结果仍然是原来的数,即a⊕0=a。
- 任何数和其自身做异或运算,结果是 0,即 a⊕a=0。
- 异或运算满足交换律和结合律,即a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。
由于此题有一个是单出来的,所以如果遍历一遍数组,然后一个变量等于数组的首元素,再依次让每个元素与那个变量做异或运算。由于任何数和自身做异或运算的时候等于0,那么相同的数字就被消除掉了,最终得到的结果即为单出来的那个数。
- 时间复杂度:O(n),其中 nn 是数组长度。只需要对数组遍历一次。
- 空间复杂度:O(1)。
运行结果
源代码
class Solution:
def singleNumber(self, nums: List[int]) -> int:
result = nums[0]
for i in range(1,len(nums)):
result = result^nums[i]
return result
还有的大佬用匿名函数,一行代码就解决了这个问题。参考如下:
class Solution:
def singleNumber(self, nums: List[int]) -> int:
return reduce(lambda x, y: x ^ y, nums)
可见其用时稍微快点,但内存消耗是一样的。
总结反思
从这个题目中学到了位运算中的异或运算,匿名函数,reduce函数。
-
位运算。从菜鸟教程中了解到:
对于左移动运算符,高位丢弃,低位补0;对于右移动运算符,低位丢弃,高位补0。 -
匿名函数
语法:lambda [arg1 [,arg2,…argn]]:expression
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。 -
reduce() 函数。
语法: reduce(function, iterable[, initializer])
用法: 会对参数序列中元素进行累积,需引入 functools 模块来调用 reduce() 函数。
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。