LeetCodeAnimation/notes/LeetCode第136号问题:只出现一次的数字.md
程序员吴师兄 5dee53d957 更换图片地址
2019-11-14 11:00:28 +08:00

88 lines
2.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LeetCode 136 号问题只出现一次的数字
> 本文首发于公众号五分钟学算法[图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>)系列文章之一。
>
> 个人网站[https://www.cxyxiaowu.com](https://www.cxyxiaowu.com)
题目来源于 LeetCode 上第 136 号问题只出现一次的数字题目难度为 Easy目前通过率为 66.8%
### 题目描述
给定一个**非空**整数数组除了某个元素只出现一次以外其余每个元素均出现两次找出那个只出现了一次的元素
**说明**
你的算法应该具有线性时间复杂度 你可以不使用额外空间来实现吗
**示例 1:**
```
输入: [2,2,1]
输出: 1
```
**示例 2:**
```
输入: [4,1,2,1,2]
输出: 4
```
### 题目解析
根据题目描述由于加上了时间复杂度必须是 O(n) 并且空间复杂度为 O(1) 的条件因此不能用排序方法也不能使用 map 数据结构
程序员小吴想了一下午没想出来答案是使用 **位操作Bit Operation** 来解此题
将所有元素做异或运算即a[1] a[2] a[3] a[n]所得的结果就是那个只出现一次的数字时间复杂度为O(n)
### 异或
异或运算A B的真值表如下
| A | B | |
| :--- | :--: | ---: |
| F | F | F |
| F | T | T |
| T | F | T |
| T | T | F |
### 动画演示
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/8720h.gif)
### 进阶版
有一个 n 个元素的数组除了两个数只出现一次外其余元素都出现两次让你找出这两个只出现一次的数分别是几要求时间复杂度为 O(n) 且再开辟的内存空间固定( n 无关)
#### 示例 :
输入: [1,2,2,1,3,4]
输出: [3,4]
### 题目再解析
根据前面找一个不同数的思路算法在这里把所有元素都异或那么得到的结果就是那两个只出现一次的元素异或的结果
然后因为这两个只出现一次的元素一定是不相同的所以这两个元素的二进制形式肯定至少有某一位是不同的即一个为 0 另一个为 1 现在需要找到这一位
根据异或的性质 `任何一个数字异或它自己都等于 0 `得到这个数字二进制形式中任意一个为 1 的位都是我们要找的那一位
再然后以这一位是 1 还是 0 为标准将数组的 n 个元素分成两部分
- 将这一位为 0 的所有元素做异或得出的数就是只出现一次的数中的一个
- 将这一位为 1 的所有元素做异或得出的数就是只出现一次的数中的另一个
这样就解出题目忽略寻找不同位的过程总共遍历数组两次时间复杂度为O(n)
### 动画再演示
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/5uz1n.gif)
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/2hfta.png)