ACWING74. 数组中唯一只出现一次的数字(剑指offer,状态机,二进制)

在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。

请找出那个只出现一次的数字。

你可以假设满足条件的数字一定存在。

思考题:

如果要求只使用 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;
    }
};

发布了843 篇原创文章 · 获赞 28 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/105001697
今日推荐