【剑指offer】【位运算】56 - II. 数组中数字出现的次数 II

题目链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/

思路

关键点

还是从位运算的角度,考虑数字的二进制形式,各二进制位出现的次数都是3的倍数。说明出现了三次;因此,统计所有数字的各二进制位中1出现次数,并对3求余,结果为只出现一次的数字;

逐位统计

时间复杂度:O(32*n)≈ O(n)
空间复杂度:O(1)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        vector<int> count(32, 0);
        for(auto num : nums)
            for(int i = 0; i < 32; i++)
            {
                //获取二进制数字 num 的最右一位
                count[i] += num & 1;
                //右移一位
                num >>= 1;
            }
        int res = 0;
        for(int i = 0; i < 32; i++)
        {
            //左移 1 位
            res <<= 1;
            //将count数组中各二进位的值恢复到数字res上
            res |= count[31 - i] % 3;
        }
        return res;
    }
};

位运算 + 状态转移

时间复杂度:O(n)
空间复杂度:O(1)
基本想法,统计每一位出现0还是1
先考虑遍历一个数的每一位的情况:
遇到0,不变;
遇到1, 00 -> 01 -> 10 -> 00 三种状态之间循环
遍历完所有数字后,各二进制位都处于状态 00 和状态 01 (取决于 “只出现一次的数字” 的各二进制位是 11 还是 00 ),而此两状态是由 once 来记录的(此两状态下 twice 恒为 00 ),因此返回 once 即可。
如果,一个数出现了三次,状态是00;如果出现了一次,状态就是01,once上存的就是结果;

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int once = 0, twice = 0;
        for(auto x : nums)
        {
            once = once ^ x & ~twice;
            twice = twice ^ x & ~once;
        }
        return once;
    }
};
posted @ 2020-04-23 13:37  NaughtyCoder  阅读(91)  评论(0)    收藏  举报