260. Single Number III (位运算)

LeetCode-260.Single Number III

Description

Given an array of numbers nums, in which exactly two elements appear only once and 
all the other elements appear exactly twice. Find the two elements that appear 
only once.

Example

Input:  [1,2,1,3,2,5]
Output: [3,5]

Note

  1. The order of the result is not important.

  2. linear runtime complexity. only constant space complexity

Solution

   之前做过这个 Single Number 系列的前两个版本: LeetCode- 137.Single Number II (位运算), 并提供了使用位运算的解法.

   与之前解法不同, 该题 Single Number III 中最终的解不止一个, 而是有两个不同的解。

   首先想到的应该与前两个系列的题一样的思路, 使用运算符 ^, & 用 x1, x2… 等来保存每个数出现的次数等思想。 但是该题最终有两个结果, 如 Example 中的 3, 5, 这样, 直接使用异或操作 x ^= nums[i] 之后, 最终 x 中存的是 35 两个数的异或结果。

   参考别人的思路, 这里要想办法将所有数划分为两类, 一类包含 3, 另一类包含 5, 并且相同数将在同一类中。 使用 a^ 第一类, 使用 b^ 第二类, 最终得到的结果中, a 就是第一个要求的结果, b 就是第二个要求的结果。 返回 a, b 就是最终要求的两个数。

   具体的划分规则, 这里采用的是利用 x倒数第一个 1 来划分(注意 x 是所有数 ^ 的结果)。 利用位运算 (x & (x-1)) ^ x 即可得到 x 的最后一个 1, 使用变量 lastbit 记录。 其中重要的一条是: x最后一个 1 只能是由 35 其中的一个数提供, 要么是 3, 要么是 5 (异或操作)。

3 : "011",  5 : "101"   3 ^ 5 : "110"
=> lastbit: "010", 只有一个 1, 并且由 3 提供

   最终, 再次遍历所有元素, 将每个元素 elelastbit 进行 & 运算, 根据 & 运算结果将所有数划分为两类, 分别进行 ^ 运算。

Code

class Solution {
public:
    vector singleNumber(vector& nums) {
        int x = 0, y;
        vector retvec;
        for(int ele : nums) x ^= ele;
        
        // 取 x 的最后一位
        int lastbit = (x & (x - 1)) ^ x;
        
        // lastbit 只可能由最后结果 a, b 中的一个提供
        // 因此, 以 lastbit 为依据, 将 a, b 划分到不同组, 
        // 并且同组中出现过两次数的都将变为零
        
        int a = 0, b = 0;
        for(int ele : nums) {
            if(ele & lastbit) a ^= ele;
            else b ^= ele;
        }
        
        return vector{a, b};
    }
};

你可能感兴趣的:(C/C++,Leetcode,算法)