LeetCode/solutions/137. Single Number II.md
2019-08-08 14:53:52 +08:00

70 lines
2.3 KiB
Markdown
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.

# [137. Single Number II](https://leetcode.com/problems/single-number-ii/)
# 思路
这道题是 [136. Single Number](https://leetcode.com/problems/single-number/)的拓展136的解法就是利用计算机按位储存数字的特性来做的
这道题就是除了一个单独的数字之外,数组中其他的数字都出现了三次,由于需要线性复杂度,所以还是要利用位操作。
## 思路一
我们可以建立一个32位的数字来统计每一位上1出现的个数我们知道如果某一位上为1的话
那么如果该整数出现了三次对3去余为0我们把每个数的对应位都加起来对3取余最终剩下来的那个数就是单独的数字。
## 思路二
将思路一的计数过程也改成位操作将会更简洁。我们用整数one表示出现了1次two表示出现了2次当出现3次的时候清零。
可以列出状态转换表(《数字电路》课程里面貌似叫做真值表)如下:
|编号| input | one | two| new_one |new_two| 备注|
|--| ---| --- | -- |------ |----- | ---|
|1| 0 | 0 | 0 | 0| 0| |
|2| 0 | 0 | 1 | 0| 1| |
|3| 0 | 1 | 0 | 1| 0| |
|4| 1 | 0 | 0 | 1| 0| |
|5| 1 | 0 | 1 | 0| 0| 三个1清零 |
|6| 1 | 1 | 0 | 0| 1| |
注意上表中不可能出现one和two都为1的情况。根据上表我们可以写出状态表达式:
```
根据表格第3、4行:
new_one = [(~input) & one & (~two)] | [input & (~one) & (~two)] = (input ^ one) & (~two)
同理根据第2、6行:
new_two = [(~input) & two & (~new_one)] | [input & (~two) & (~new_one)] = (input ^ two) & (~new_one)
```
(学过《数字电路》的同学可能更好理解上述化简过程)
# C++
## 思路一
``` C++
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = 0;
for(int i = 0; i < 32; i++){
int count = 0;
for(int j = 0; j < nums.size(); j++){
count += ((nums[j] >> i) & 1);
}
count %= 3;
res |= count * (1 << i);
}
return res;
}
};
```
## 思路二
``` C++
class Solution {
public:
int singleNumber(vector<int>& nums) {
int one = 0, two = 0;
for(auto &num: nums){
one = (~two) & (one ^ num);
two = (~one) & (two ^ num);
}
return one;
}
};
```