这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
题目描述:
136. 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例一
输入: [2,2,1]
输出: 1
示例二
输入: [4,1,2,1,2]
输出: 4
思路分析
此题中有2个条件
- 除了某个元素只出现一次以外,其余每个元素均出现两次
- 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
抛开第二个条件的话,我们有很多种解法,排序暴力解法,HashSet,HashMap等等
但是这些解法的空间复杂度都超了
要是满足第二个条件的话,可以使用异或位运算(不看题解打死想不到系列 - -)
排序法
略
HashMap
使用HashMap来统计数组中某元素出现的次数是一个很正常的思路了,key为元素,value为次数,最终我们只要找到value为1的key就行了。
代码较为简单,略。
HashSet
HashSet有个特性就是不允许重复添加数据,所以利用这个特性,我们只要遍历一遍,往HashSet添加数据,如果添加失败,就说明这个数据之前添加成功过,也就是出现了2次了,我们只要从HashSet删除这个数据就行,最终剩下的自然就是只出现一次的数据了。
AC代码
class Solution {
fun singleNumber(nums: IntArray): Int {
val set = mutableSetOf<Int>()
for (i in 0..nums.lastIndex) {
if (!set.add(nums[i])) {
set.remove(nums[i])
}
}
return set.iterator().next()
}
}
按位异或(xor)
异或解法:异或运算满足交换律,b,因此ans相当于nums[0]^nums[1]^nums[2]^nums[3]^nums[4]..... 然后再根据交换律把相等的合并到一块儿进行异或(结果为0),然后再与只出现过一次的元素进行异或,这样最后的结果就是,只出现过一次的元素(0^任意值=任意值)
AC代码
class Solution {
fun singleNumber(nums: IntArray) = nums.reduce() { a, b -> a.xor(b) }
}
总结
这题主要就在第二个条件,对空间复杂度有要求。
看了题解才知道异或的解法。
这边总结下异或吧。
异或运算有以下三个性质。
- 任何数和 0 做异或运算,结果仍然是原来的数,即
- 任何数和其自身做异或运算,结果是 0,即
- 异或运算满足交换律和结合律,即
参考
只出现一次的数字 - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)
学算法,结果相对于过程不那么重要 - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)
通过哈希集、按位异或操作符解决(解题思路) - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)