137. 只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,3,2]
输出: 3
示例 2:

输入: [0,1,0,1,0,1,99]
输出: 99
解法一:
创建一个长度为sizeof(int)的数组count[sizeof(int)],用count[i]来表示在i位出现的1的次数,如果count[i]是3的倍数,跳过,否则,取出该位。
时间复杂度O(n),空间复杂度O(1)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int w = sizeof(int) * 8;
        int count[w];
        fill_n(&count[0], w, 0);
        for(int i = 0; i < nums.size(); i++) {
            for(int j = 0; j < w; j++) {
                count[j] += (nums[i] >> j) & 1;
                count[j] %= 3;
            }
        }
        int res = 0;
        for(int i = 0; i < w; i++) {
            res += count[i] << i;
        }
        return res;
    }
};

解法二:
用二进制模拟三进制运算。
用one记录到当前处理的元素为止,二进制1出现“1次”(mod 3 之后的 1)的有哪些二进制位;用two记录到当前计算的变量为止,二进制1出现“2次”(mod 3 之后的 2)的有哪些二进制位。当one和two中的某一位同时为1时表示该二进制位上1出现了3次,此时需要清零。
时间复杂度O(n),空间复杂度O(1)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int one  = 0, two = 0, three = 0;
        for(auto i : nums) {
            two |= (one & i);
            one ^= i;
            three = ~(one & two);
            one &= three;
            two &= three;
        }
        return one;
    }
};

解法三:
我们把数组中数字的每一位累加起来对3取余,剩下的结果就是那个单独数组该位上的数字.
用二进制表示的过程为00->01->10->00,用a 和 b来表示一开始的状态的十位和个位:
b = b ^ r & ~a;
a = a ^ r & ~b;
刚开始的时候,a和b都是0,当遇到数字1的时候,b更新为1,a更新为0,就是01的状态;再次遇到1的时候,b更新为0,a更新为1,就是10的状态;再次遇到1的时候,b更新为0,a更新为0,就是00的状态,相当于重置了;所以最后的结果保存在b中。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int a = 0, b = 0;
        for (int i = 0; i < nums.size(); ++i) {
            b = (b ^ nums[i]) & ~a;
            a = (a ^ nums[i]) & ~b;
        }
        return b;
    }
};

参考:https://soulmachine.gitbooks.io/algorithm-essentials/java/bitwise-operations/single-number-ii.html

https://leetcode.com/problems/single-number-ii/discuss/43294/challenge-me-thx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值