只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
思路:
由于题目要求具有线性时间复杂度O(n),因而比较、排序、去重等方法不可取。
回顾一下位运算,异或,记为XOR,⊕ 。
(1)任何数与0异或都不改变它的值,即
a
⊕
0
=
a
a⊕0=a
a⊕0=a。
(2)任何数与自身异或都为0,即
a
⊕
a
=
0
a⊕a=0
a⊕a=0。
(3)交换律,
a
⊕
b
=
b
⊕
a
a⊕b=b⊕a
a⊕b=b⊕a。
(4)结合律,
a
⊕
b
⊕
c
=
a
⊕
(
b
⊕
c
)
a⊕b⊕c=a⊕(b⊕c)
a⊕b⊕c=a⊕(b⊕c)。
假设,数组为[a1, a1, a2, a2, … , an, an, ax],其中只有ax出现1次,其他的出现2次。对所有元素进行异或,利用交换律可以得到
- a1⊕a1⊕a2⊕a2⊕… ⊕an⊕an⊕ax
= (a1⊕a1)⊕(a2⊕a2)⊕… ⊕(an⊕an)⊕ax
= 0⊕0⊕…⊕0⊕ax
=ax
因此,只需要遍历一次数组,即可在线性时间复杂度下,找出这个只出现一次的数字。
代码:
int singleNumber(vector<int>& nums) {
int the_one=0;
for(auto num:nums)
{
the_one=the_one^num; //^为C语言中异或运算
}
return the_one;
}
结果:
扩展:
我们不妨复习一下同或规则,符号记为⊙。 C语言中没有同或符号,需要将异或按位取反,即 a⊙b=~(a^b)。以下是几条同或的性质:
(1)公式,
a
⊙
b
=
a
b
+
a
′
b
′
a⊙b=ab+a'b'
a⊙b=ab+a′b′。
a
′
a'
a′、
b
′
b'
b′为非a,非b。
(2)a与任意个1或偶数个0同或,结果为a。
(3)交换律,
a
⊙
b
=
b
⊙
a
a⊙b=b⊙a
a⊙b=b⊙a。
(4)结合律,
a
⊙
b
⊙
c
=
a
⊙
(
b
⊙
c
)
a⊙b⊙c=a⊙(b⊙c)
a⊙b⊙c=a⊙(b⊙c)。
参考链接:
风追云影:只出现一次的数字