LeetCode.136 只出现一次的数字

458 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

题目描述:

136. 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例一

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

示例二

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

思路分析

此题中有2个条件

  1. 除了某个元素只出现一次以外,其余每个元素均出现两次
  2. 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

抛开第二个条件的话,我们有很多种解法,排序暴力解法,HashSet,HashMap等等

但是这些解法的空间复杂度都超了

要是满足第二个条件的话,可以使用异或位运算(不看题解打死想不到系列 - -)

排序法

HashMap

使用HashMap来统计数组中某元素出现的次数是一个很正常的思路了,key为元素,value为次数,最终我们只要找到value1key就行了。

代码较为简单,略。

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)

异或解法:异或运算满足交换律,aba=aab=0b=a⊕b⊕a=a⊕a⊕b=0⊕b=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) }
}

总结

这题主要就在第二个条件,对空间复杂度有要求。

看了题解才知道异或的解法。

这边总结下异或吧。

异或运算有以下三个性质。

  1. 任何数和 0 做异或运算,结果仍然是原来的数,即 a0=aa⊕0=a
  2. 任何数和其自身做异或运算,结果是 0,即 aa=0a⊕a=0
  3. 异或运算满足交换律和结合律,即 aba=aab=0b=ba⊕b⊕a=a⊕a⊕b=0⊕b=b

参考

只出现一次的数字 - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

学算法,结果相对于过程不那么重要 - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

通过哈希集、按位异或操作符解决(解题思路) - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

只出现一次的数字(Java) - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)