136. Single Number
一、题目
Problem Description:
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
Follow up:
Could you implement a solution with a linear runtime complexity and without using extra memory?
Example 1:
Input: nums = [2,2,1]
Output: 1
Example 2:
Input: nums = [4,1,2,1,2]
Output: 4
Example 3:
Input: nums = [1]
Output: 1
Constraints:
1
<
=
n
u
m
s
.
l
e
n
g
t
h
<
=
3
∗
1
0
4
1 <= nums.length <= 3 * 10^4
1<=nums.length<=3∗104
−
3
∗
1
0
4
<
=
n
u
m
s
[
i
]
<
=
3
∗
1
0
4
-3 * 10^4 <= nums[i] <= 3 * 10^4
−3∗104<=nums[i]<=3∗104
Each element in the array appears twice except for one element which appears only once.
二、题解
- 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素都出现两次。输出这个只出现一次的元素。
2.1 Approach #1 : ArrayList
遍历nums数组中的所有元素。如果当前元素在ArrayList中不存在,则将其加入ArrayList;若存在,则将其删除。由题意,“除了某个元素只出现一次以外,其余每个元素都出现两次”可知,最后只剩一个只出现一次的元素,将其输出即可。
Time complexity :
O
(
2
n
)
O(2^n)
O(2n). 遍历nums数组,消耗
O
(
n
)
O(n)
O(n);在遍历各个元素时,都要判断当前元素是否在ArrayList中,即搜索整个ArrayList来查找是否存在重复元素,又需要
O
(
n
)
O(n)
O(n)。在for循环中,两者相乘,时间复杂度一共
O
(
2
n
)
O(2^n)
O(2n)。
Space complexity :
O
(
n
)
O(n)
O(n)
public E remove(int index);
按索引删除元素
public boolean remove(Object o);
若有值相同元素,删除第一个
//ArrayList
//Time complexity : O(2^n); Space complexity : O(n)
class Solution {
public int singleNumber(int[] nums) {
List<Integer> list = new ArrayList<Integer>();
for(Integer x : nums){
if(list.contains(x) == false){
list.add(x);
}else{
list.remove(x);//x为Integer型,删除该元素值
}
}
return list.get(0);
}
}
2.2 Approach #2 : Hash Table
思路和 Approach #1 : ArrayList 一致,只是考虑到理想情况下,HashSet / HashMap 的增、删、改、查等操作的时间复杂度都为 O ( 1 ) O(1) O(1),减少了在集合中搜索重复元素的时间复杂度。
以下以HashSet集合为例,HashMap也同理。
Time complexity :
O
(
n
)
O(n)
O(n). 遍历nums数组,消耗
O
(
n
)
O(n)
O(n);在遍历各个元素时,都要判断当前元素是否在HashSet中,理想情况下,HashSet的增、删、改、查等操作的时间复杂度都为
O
(
1
)
O(1)
O(1)。在for循环中,两者相乘,时间复杂度一共
O
(
n
)
O(n)
O(n)。
Space complexity :
O
(
n
)
O(n)
O(n)
//Hash Table
//Time complexity : O(n); Space complexity : O(n)
class Solution {
public int singleNumber(int[] nums) {
Set<Integer> s = new HashSet<Integer>();
for(Integer x : nums){
if(s.contains(x) == false){
s.add(x);
}else{
s.remove(x);
}
}
//经以上操作后,虽然HashSet中只有一个元素,但由于HashSet无索引,故可采取以下方法
for(Integer x : s){
return x;
}
return 0;
}
}
2.3 Approach #3 : Math + Hash Table
2
∗
(
a
+
b
+
c
)
−
(
a
+
a
+
b
+
b
+
c
)
=
c
2*(a+b+c)−(a+a+b+b+c)=c
2∗(a+b+c)−(a+a+b+b+c)=c
纯碎的数学思维解题,直接看公式就能理解此方法的思路。
将每次遍历的元素相加,得到
(
a
+
a
+
b
+
b
+
c
)
(a+a+b+b+c)
(a+a+b+b+c);
通过HashSet集合判断是否是重复元素,可计算出
(
a
+
b
+
c
)
(a+b+c)
(a+b+c);
最后通过公式:
2
∗
(
a
+
b
+
c
)
−
(
a
+
a
+
b
+
b
+
c
)
=
c
2*(a+b+c)−(a+a+b+b+c)=c
2∗(a+b+c)−(a+a+b+b+c)=c,即可得到所求结果。
Time complexity :
O
(
n
)
O(n)
O(n)
Space complexity :
O
(
n
)
O(n)
O(n)
//Math + Hash Table
//2*(a+b+c)−(a+a+b+b+c)=c
//Time complexity : O(n); Space complexity : O(n)
class Solution {
public int singleNumber(int[] nums) {
Set<Integer> s = new HashSet<Integer>();
int sumOfSet = 0;
int sumOfNums = 0;
for(Integer x : nums){
if(s.contains(x) == false){
s.add(x);
sumOfSet += x;
}
sumOfNums += x;
}
return 2 * sumOfSet - sumOfNums;
}
}
2.4 Approach #4 : Bit Manipulation (XOR)
Could you implement a solution with a linear runtime complexity and without using extra memory?
要求不能使辅助空间,并且时间复杂度只能是线性的。
every element appears twice except for one
只有一个数字出现一次,其余数字都出现两次。想到了异或运算的性质:① 任意数字异或其本身都等于0; ② 任意元素异或0结果为其本身。也就是说,异或数组中的每一个元素,那么最终的结果正是只出现一次的数字,因为其他出现两次的数字在异或其本身时结果都为0。
If we take XOR of zero and some bit, it will return that bit.
a
⊕
0
=
a
a⊕0=a
a⊕0=a
If we take XOR of two same bits, it will return 0.
a
⊕
a
=
0
a⊕a=0
a⊕a=0
a
⊕
b
⊕
a
=
(
a
⊕
a
)
⊕
b
=
0
⊕
b
=
b
a⊕b⊕a=(a⊕a)⊕b=0⊕b=b
a⊕b⊕a=(a⊕a)⊕b=0⊕b=b
Time complexity :
O
(
n
)
O(n)
O(n)
Space complexity :
O
(
1
)
O(1)
O(1)
//Bit Manipulation (XOR)
//Time complexity : O(n); Space complexity : O(1)
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for(int x : nums){
res ^= x;
}
return res;
}
}