在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。
请找出那个只出现一次的数字。
你可以假设满足条件的数字一定存在。
思考题:
如果要求只使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
样例
输入:[1,1,1,2,2,2,3,4,4,4]
输出:3
参考:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/solution/zhuang-tai-ji-jie-jue-ci-wen-ti-xiang-jie-shu-zi-d/
刚刚才写完数电作业,这里就遇到了电路设计题,果然知识都是相通的啊。。。。
思路:
解法一: 对所有数字,将统计每一个二进制位1的数目,如果1的数目模3余1,那么此位为1.
解法二:
很巧妙,使用了状态机的知识。但是本题,只要知道电路设计(或者位运算)的知识就足矣。
可以利用两位二进制数:ab,用于表示一个三进制位的状态,代表1的个数余3的值。
初始化a = 0,b = 0.
值为0: a = 0,b = 0
值为1: a = 1,b = 0
值为2: a = 0,b = 1
假设加入的值为c, c为0就是没有输入,c为1就是输入
列出真值表为
由真值表可以得出
New_a = a’b’c’ + ab’c
对于a:
New_a = b’(a’c + ac’) = a^c & b’
对于b:
此时a已经发生了变换变成了New_a。
同样的利用中的New_a,b,c,
可以得到:
b = New_a’bc’ + New_a’b’c
b = New_a’ (b ^ c)
class Solution {
public:
int findNumberAppearingOnce(vector<int>& nums) {
int a = 0,b = 0;
int n = nums.size();
for(int i = 0;i < n;i++) {
a = (a ^ nums[i]) & ~b;
b = (b ^ nums[i]) & ~a;
}
return a;
}
};
不化简的话就直接根据真值表中初始a,b,c写
class Solution {
public:
int findNumberAppearingOnce(vector<int>& nums) {
int a = 0,b = 0;
int n = nums.size();
for(int i = 0;i < n;i++) {
int x = a;
a = (x & ~b & ~nums[i]) | (~x & ~b & nums[i]);
b = (~b & nums[i] & x) | (b & ~nums[i] & ~x);
}
return a;
}
};