LeetCode-137:Single Number II (只出现一次的数字)

题目:

Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:

  • Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

例子:

Example 1:

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

Example 2:

Input: [0,1,0,1,0,1,99]
Output: 99

问题解析:

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

链接:

思路标签

位运算状态机

解答:

  • 和LeetCode 136:Single Number属于类似的问题,136中给出其他元素均出现两次,我们使用“异或”运算,即:0^a=aa^a=0,即可求得结果;
  • 但是当元素上升到3个及3个以上时,就无法继续使用这么简单的方法来实现了,下面给出三种实现方法,其中后面的两种是相同的,同时第一种和最后一种方法对于任意一个重复K次的相似问题均是通用的。

1. 统计每一位1的个数,和对3取余

  • 对每个整数以32位表示,分别统计每一位上1的个数,最后该位数上的和对3取余数;
  • 如果余数不为0,则说明该位上只出现一次的元素,在该位上有1;
  • 通过移位操作和1做位与运算,则可求得当前元素在该位是否有1。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for(int i=0; i<32; ++i){
            int sum = 0;
            for(int j=0; j<nums.size(); ++j){
                sum += (nums[j]>>i) & 1;
            }

            ret |= (sum % 3)<<i;
        }

        return ret;
    }
};

2. 状态机法,用2个数分别表示状态机的3个状态

  • 利用状态机表示:我们用下面的三种状态来表示对于某个数字出现了多少次:00、01、10、00,也就是我们累加的过程0——>1——>2——>0,当满3个数字时则记为0次。
  • 所以,我们可以用两个整数(32位)来表示所有数中每一位上出现1的次数。例子:ones的第3位为1,twos的第3位为0,则表示当前累计的所有元素中,各个元素的第3位上出现1的个数为2个。
  • 写出对应关系:
    • 00 (+) 1 = 01
    • 01 (+) 1 = 10
    • 10 (+) 1 = 00 ( mod 3)
  • 那么我们用ab来表示开始的状态,对于加1操作后,得到的新状态的ba(其中a表示倒数第一位,b表示倒数第2位)的算法如下:
    • a = a xor r & ~b;
    • b = b xor r & ~a;
  • 因为我们最后要求的是只出现1次的元素,所以通过对所有元素的位运算后,32个位上出现1只有一次的元素就是我们要返回的元素,也就是ones当前保存的元素。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ones = 0, twos = 0;
        for(int i=0; i<nums.size(); ++i){
            ones = (ones^nums[i]) & ~twos;
            twos = (twos^nums[i]) & ~ones;
        }
        return ones;
    }
};

3. 状态机法,用K-1个数分别表示状态机的K个状态(通法)

  • 下面的解法是与解法2同样思想的解法,但其可以解决任意K个重复元素的问题。
  • 同时,对于不同的K,假设只有一个元素重复3次,其余重复K次,K>3,那么我们还可以用下面的方法返回bits[2]来得到该返回元素,具体就不展开分析。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        return singleNumber(nums, 3);
    }

    int singleNumber(vector<int>& nums, int _K) {
        int K = _K - 1;
        int bits[K] = {0};
        for (int num : nums) {
            for (int i = 0; i < K; i++) {
                int mask = -1;
                for (int j = 0; j < K; j++) if (j != i)
                    mask &= ~bits[j];
                bits[i] = (bits[i] ^ num) & mask;
            }
        }
        return bits[0];
    }
};
点赞