今日题目: 只出现一次的数字 (2021.10.30 )

156 阅读2分钟

今日题目: 只出现一次的数字

只出现一次的数III

1.题目描述(2021.10.30 )

    给定一个整数数组 `nums`,其中恰好有两个元素只出现一次,其余所有元素均出现两次。
    找出只出现一次的那两个元素。你可以按 **任意顺序** 返回答案。

2.解题思路

1.看到重复元素,第一时间想到哈希表。理所应当的HashSet 或者HashMap 一遍过,但是
hash并非是最优解。
2.看了答案,但是看不懂。去翻资料,温故而知新。

3. 题解

```
   public int[] singleNumber(int[] nums) {
    int xorsum = 0;
    //1. 获得异或值
    for (int num : nums) {
        xorsum ^= num;
    }
    // 防止溢出
    //2.利用异或值进行分类运算。
    int lsb = (xorsum == Integer.MIN_VALUE ? xorsum : xorsum & (-xorsum));
    int type1 = 0, type2 = 0;
    for (int num : nums) {
        if ((num & lsb) != 0) {
            type1 ^= num;
        } else {
            type2 ^= num;
        }
    }
    return new int[]{type1, type2};
}
```

为了省事我就直接搬官方答案,很多人在第一步能理解,到第二步就开始不太明白,那么接着往下看。

4. 知识点以及说明

知识点1 : 正数的原码,补码,反码都是一样的。

知识点2 : 计算机中,所有的负数参与运算时,都是以补码参与。

关于原码,补码的知识,如果有不清楚的,可以看这篇文章

原码以及补码知识点

那么回头看解析,为什么要进行 lsb = xorm & -xorm 这一步,我们用刚复习的补码知识将答案一步步拆解。

举个例子:假如xorm = 6 ,对于lsb = xorm & -xorm ,用4位二进制表示时6的二进制是 0110 ,-6 的二进
制是1110,-6 的 补码就是 1010 , 计算时,负数带入补码计算 (0110)&(1010) = 0010 ,那么这个数字的意
思就是,原数组中只出现1次的两个数字,用二进制表示后的它们,在第二位必然是以一个0 一个1 出现的。那么
可以对数组中的元素进行分流处理。 因为 a^a = 0 ,a^0 = a 这一特性,将数组分为两类进行异或处理,最后
所剩余的值,就是我们要求的解。

5. 总结

学到了新的知识,感觉又变强了

QQ图片20211030233437.jpg