Solve 0137

This commit is contained in:
Yuhang Peng 2020-05-09 16:00:38 -07:00
parent 76b7c5f2ad
commit 1c55e0bedc
3 changed files with 50 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

Binary file not shown.

View File

@ -0,0 +1,50 @@
# LeetCode 137 号问题只出现一次的数字
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 137 号问题只出现一次的数字 II题目难度为 Medium目前通过率为 66.7%
### 题目描述
给定一个非空整数数组除了某个元素只出现一次以外其余每个元素均出现了三次找出那个只出现了一次的元素
说明
你的算法应该具有线性时间复杂度 你可以不使用额外空间来实现吗
**示例 1:**
```
输入: [2,2,3,2]
输出: 3
```
**示例 2:**
```
输入: [0,1,0,1,0,1,99]
输出: 99
```
### 题目解析
相比 [Single Number](https://leetcode.com/problems/single-number/)输入数组的条件变了数组中除了其中的一个元素只出现了一次其余的元素都出现了 **** 最后的问题还是让你找出这个只出现一次的元素这道题目一开始看起来从位运算思考貌似是不可能的但如果你从集合的角度去思考或许可以想到解法如果我们遍历数组里面的元素在遍历的过程中我们会发现 **对于每个元素来说只有三种情况出现一次出现两次出现三次**因为我们要找的是出现一次的那个元素而且最终除了我们要找的元素其他所有的元素都会出现三次因此我们需要想办法排除掉出现三次的元素一开始的时候可以想我们用两个集合集合 1 用于存放出现一次的元素集合 2 用于存放出现两次的元素于是我们可以发现下面的逻辑对应关系
```
如果遍历到的元素不在集合 1 也不在集合 2 该元素第一次出现加入集合 1
如果遍历到的元素在集合 1 不在集合 2 该元素第二次出现移出集合 1加入集合 2
如果遍历到的元素不在集合 1 在集合 2 该元素第三次出现移出集合 2
```
上面的逻辑对应关系你应该很容易理解但是我想说的是通过位操作可以做到这一点我们不需要真正的集合我们只需要用一个整数来代替集合即可怎么解释呢假设我们用整数 `ones` 表示集合 1整数 `twos` 表示集合 2这两个整数的值初始化均为 0`ones ^ ele[i]` 表示把元素 `ele[i]` 加入到集合 1 如果说下一个元素 `ele[i + 1]` 来了并且 `ele[i] != ele[i + 1]`那么 `ones ^ ele[i] ^ ele[i + 1]` 肯定会产生一个不为零的值至于这个值是多少你不用关心但如果 `ele[i] == ele[i + 1]`那么 `ones ^ ele[i] ^ ele[i + 1]` 的结果肯定为 0到这里你应该知道通过异或运算我们已经可以做到将出现一次的元素加入集合 1将出现两次的元素移出集合 1但是这还不够因为元素还有可能出现三次如果仅仅是上面的异或表达式第三次出现的元素还是会被加入到集合 1我们还需要保证该元素不在集合 2 `(ones ^ ele[i]) & (~twos)` 就可以保证这一点对集合 2 来说也是一样的`(twos ^ ele[i]) & (~ones)` 保证将不存在于集合 1 且不存在集合 2 中的元素加入到集合 2如果我们先更新集合 1再更新集合 2就可以实现我们之前说的逻辑对应关系说到这里如果你还是不理解那么你 **可以尝试把一个元素看作是一堆值为 1 bit 位的组合**比如 12 的二进制是 `0001 0100`如果说 12 出现了三次那么从右往左数第三位和第五位 bit 的就出现了三次我们把这个结论放在数组中也是一样的对于那些出现了 3 的整数倍次的 bits 位我们要进行消除找到那些出现了 `3 * n + 1` 次的 bit 将它们组合在一起就是我们要找的元素上面的位运算做的就是这个事情与其说把元素放入集合中我们也可以说 **将元素的所有值为 1 bit 位放入集合中**这样会更好理解些
<br>
### 动画演示
![](../Animation/137.gif)
![](../../Pictures/qrcode.jpg)