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

2.3 KiB
Raw Blame History

137. Single Number II

思路

这道题是 136. 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++

思路一

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;
    }
};

思路二

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;
    }
};