LeetCode题解:Single Number II

Given an array of integers, every element appears three times except for one. Find that single one.

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

题意:给定一个数组,除了某个元素只出现一次,每个元素都出现三次。找出只出现一次的数。要求O(n)时间,O(1)空间

解题思路:最开始对这道题毫无思路,后来看了LeetCode上面的解法也还是看不太懂,想了好久,结合Single Number最终理解过来了:

先回顾Single Number吧,Single Number中每个数出现两次,只有一个数出现了1次,于是我们选择了异或运算,因为异或运算完美满足要求。但是,为什么异或能解决这个问题呢?

首先,解决这个问题我们要做的是-记录所有数出现的次数,次数为1的就是要找的。这是最直观的解法,也是O(n)空间的解法。但是,记录次数一定要拿O(n)空间来记录吗?不妨换个角度,设result为最终结果,每个数都能以二进制表示,而大部分数又出现了两次,那么可以得到:二进制表示的某个数的某一位为1时,第一次出现该数时,result那一位也是1;如果该数是重复的数,那么第二次出现时,该位变为0,因为result那一位只会显示只出现一次的数那一位对应的0/1。如果那一位是0,那么result那一位就一直是0了。那么有:

result op 0 = result
result op 1 -> result’ & result’ op1 = result 即 result op 1 op 1 = result

这样就可以得到op为异或运算了。但这样的办法不能直接应用到这一题中,因为此时result对应的位的值会是0->1->2->3/0,即三进制计数。此时有4种状态:出现0次,1次,2次,3次,那么可以用2位表示这4种状态,即:

00 - 0次
01 - 1次
10 - 2次
11 - 3次

我们用one代表第一位,two代表第二位的话,当one == 1 && two == 1,one = 0, two = 0

而two其实就是计数当前出现次数是奇数还是偶数(11的时候自动归0),所以two = two ^ num

所以接下来只要得到one的表达式就可以解决这题了。当one=0,two=0时,下一个状态one=0;当one=0,two=1时,下一个状态one=1;当one=1,two=0时,下一个状态one=1;也就是说,当two=0,下一个状态one不变;当two=1,下一个状态one=~one。即当前one的值受上一个状态two的值影响,只有在two=1(某个数出现了奇数次)且本次循环再次出现该数,让two=0(出现偶数次),one才会变化,而:

one op 0 = one
one op 1 = one’ one’ op 1 = one 即one op 1 op 1 = one

所以one = one ^ (two & num)

所以最终就可以求出该数了,因为我们对每一位都进行了三进制计数。

代码:

public int singleNumber(int[] A) {
     int x1 = 0;   
     int x2 = 0; 
     int mask = 0;

     for (int i : A) {
        x2 ^= x1 & i;
        x1 ^= i;
        mask = ~(x1 & x2);
        x2 &= mask;
        x1 &= mask;
     }

     return x1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值