力扣(LeetCode)137. 只出现一次的数字 II

93 阅读1分钟

力扣(LeetCode)137. 只出现一次的数字 II

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。 请你找出并返回那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。

示例 1:

输入: nums = [2,2,3,2]
输出: 3

示例 2:

输入: nums = [0,1,0,1,0,1,99]
输出: 99

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

思路:

电路设计,设计出真值表后转化为逻辑表达式。 3个相同的数输入时,让其转化为0,比如初始时是0,0->1->2->0,输入为1时需要转换,为0时无影响

class Solution {
    public int singleNumber(int[] nums) {
        // ai 表示a的二进制第i位,bi同理
        // x 表示num对应的二进制位
        // nai表示当前状态为ai、bi,经过输入x后,ai的下一状态,nbi同理
        // ai bi  x   nai nbi
        // 0  0   0   0   0
        // 0  0   1   0   1
        // 0  1   0   0   1
        // 0  1   1   1   0
        // 1  0   0   1   0
        // 1  0   1   0   0

        // 真值表转逻辑表达式,找1(或0,数量少的优先),
        // 将输入变为1后"与"exp1=(!ai & bi & x)、exp2=(ai & !bi & !x),
        // 所有为1的exp“或” nextVal=exp1 | exp2
        // nai = (!ai & bi & x) | (ai & !bi & !x)
        // nbi = (!ai & !bi & x) | (!ai & bi & !x)
        
        // 三个重复 + 单个数,结果只有 00,01
        int a = 0, b = 0;
        for (int num : nums) {
            int na = (~a & b & num) | (a & ~b & ~num);
            int nb = (~a & ~b & num) | (~a & b & ~num);
            a = na;
            b = nb;
        }
        return b;
    }
}