LeetCode中只出现一次的数字题解


LeetCode中“只出现一次的数字”题解

题目

136. 只出现一次的数字

难度 简单

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

说明:

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

示例 1:

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

示例 2:

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

题解

思考:

这题拿到手,第一反应是用hash表,没有思考细节,只是觉得hash表肯定是可以搞定的,但是空间复杂度是 O(n)O(n),不满足题意。

接着开始思考,如何才能做到空间复杂度是 O(1)O(1) 呢?

心想,如果使用暴力破解法,每次从数组中取一个数,记为number,然后从剩下的数中查找,如果找不到,则number即为要找的那个数。这种解法时间复杂度是 O(n^2)O(n2)。

如何能把时间复杂度降到 O(n)O(n),有两个突破点:

暴力解法做了很多重复的工作
要充分利用题目的已有信息
通过第二点,找到了一个很重要的信息:除了某个元素只出现一次以外,其余每个元素均出现两次——异或运算,异或运算会把出现两次的值异或为0剩下的即为唯一值与0异或,还是这个唯一值

方法一:暴力查找

两次循环,代码略

方法二:排序

使用快速排序,复杂度O(nlogn)

方法三:hashmap哈希表

class Solution {
    public int singleNumber(int[] nums) {
        // 创建hashmap,键为对应值在数组nums中出现的次数
        HashMap<Integer, Integer> map = new HashMap<>();
        // 遍历数组,存入hashmap
        for (int i = 0; i < nums.length; i++) {
            // 获取此值在hashmap中的次数
            Integer count = map.get(nums[i]);
            // 将count++,如果第一次出现,将count赋值为1
            count = count == null ? 1 : ++count;
            // 将其值及其对应出现次数存入hashmap中
            map.put(nums[i], count);
        }
        // 遍历hashmap哈希表
        for (Integer value : map.keySet()) {
            // 如果出现次数为1,将对应值返回
            Integer count = map.get(value);
            if (count == 1) {
                return value;
            }
        }
        return -1; // can't find it.
    }
}
复杂度分析:

​ 时间复杂度:O(n)

​ 空间复杂度:O(N)

方法四:异或运算

异或运算

运算法则:
  1. a ^ b = b ^ a

  2. a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

  3. d = a ^ b ^ c 可以推出 a = d ^ b ^ c.

  4. a ^ b ^ a = b.

    异或运算

     1、异或是一个数学运算符。应用于逻辑运算。
     2、例如:真异或假的结果是真,假异或真的结果也是真,真异或真的结果是假,假异或假的结果是假。就是说两个值相 异结果为真。

    n^0=n n^n=0,即任何数与0进行异或,为它本身,两个相同的数进行异或运算,会得到0。

    一道有意思的题目:

    ​ 很多成对出现数字保存在磁盘文件中,注意成对的数字不一定是相邻的,如2, 5,3, 4, 7,3, 4, 2,5……,由于意外有一个数字消失了,如何尽快的找到是哪个数字消失了?

    ​ 思路:由于有一个数字消失了,那必定有一个数只出现一次而且其它数字都出现了偶数次。用搜索来做就没必要了,利用异或运算的两个特性,代码与此题类似,同一问题

 ##### 特性

 1.自己与自己异或结果为0,

 2.异或满足 交换律。
class Solution {
    public int singleNumber(int[] nums) {
        // 初始化res 为 nums[0] 
        int res = nums[0];
        // 遍历数组,依次进行异或运算,由于异或运算具有交换性,所以最后的结果即为出现一次的数与0异或
        for(int i = 1; i < nums.length; i++){
            res ^= nums[i];
        }
        // 返回此数
        return res;
    }
}
复杂度分析

​ 时间复杂度:O(N)

​ 空间复杂度:O(1)


文章作者: Loole
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Loole !
评论
  目录