#面试题 找出数组中的唯一值
数组中仅有一个元素出现了一次, 其他元素均出现了两次, 找出其中的唯一值, 如数组: [3 4 5 2 3 4 5], 2只出现了一次,即要找出2.
解法1(sort):
/**
* 算法1
* 1. 先排序
* 2. 若a[i+1]!=a[i] (i为偶数)或a[i+1]不存在 则a[i]为唯一元素
*
* [3 4 5 2 3 4 5]
* [2 3 3 4 4 5 5]
* a[1]!=a[0] ==> a[0]为唯一元素
*
* [3 4 5 2 2 4 5]
* [2 2 3 4 4 5 5]
* a[3]!=a[2] ==> a[2]为唯一元素
* [3 4 5 2 2 4 3]
* [2 2 3 3 4 4 5]
* a[7]不存在 ==> a[6]为唯一元素
* @param a
*/
public static int findUniqueValue1(final int[] a){
int[] b = a.clone();
Arrays.sort(b);
int result = -1;
for (int i = 0; i < b.length; i+=2) {
if(i+1==b.length || b[i+1]!=b[i]){
result = b[i];
break;
}
}
return result;
}
解法2(map):
/**
* 算法2
* 利用 map<a[i], null>
* 如果key(a[i])已存在 直接删除 若不存在 添加
* 最后剩下唯一的key即为所求的唯一元素
* @param a
*/
public static int findUniqueValue2(final int[] a){
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < a.length; i++) {
if(map.containsKey(a[i]))
map.remove(a[i]); //off
else
map.put(a[i], null); //on
}
int result = -1;
for (Integer key : map.keySet())
result = key;
return result;
}
解法3(位数组):
/**
* 算法3
* 利用位数组 Bit[] bits
* 如果key(a[i])不存在 bits[a[i]]=1 若已存在 bits[a[i]]=0
* 最后bits数组中等于1的索引值即为所求值
* 如
* 数组 a: [3 4 5 2 3 4 5]
*
* init bit array: [0 0 0 0 0 0]
* [0 0 0 1 0 0]
* [0 0 0 1 1 0]
* [0 0 0 1 1 1]
* [0 0 1 1 1 1]
* [0 0 1 0 1 1]
* [0 0 1 0 0 1]
* [0 0 1 0 0 0]
* @param a
* @param max 数组中的最大值
*/
public static int findUniqueValue3(final int[] a, int max){
BitSet bitSet = new BitSet(max);
for (int i = 0; i < a.length; i++){
bitSet.flip(a[i]);
}
int result = -1;
for (int i = 0; i <= max; i++) {
if(bitSet.get(i)){
result = i;
break;
}
}
return result;
}
解法4(异或):
/**
* 算法4
* 利用自己与自己异或为0的特点 如 3 ^ 3 = 0
* [3 4 5 2 3 4 5]
* 3^4^5^2^3^4^5=2
* @param a
*/
public static int findUniqueValue4(final int[] a){
int t=a[0] ;
for (int i = 1; i < a.length; i++)
t ^= a[i];
return t;
}
下面是对上述四种算法的性能比较:
算法1(sort) | 算法2(map) | 算法3(bit array) | 算法4(异或) | |
1 | 351 | 422 | 55 | 24 |
2 | 244 | 342 | 57 | 1 |
3 | 135 | 298 | 11 | 1 |
4 | 136 | 168 | 10 | 0 |
5 | 135 | 366 | 12 | 1 |
注: 数组大小为1,000,001, 一共运行了5次, 在循环内部分别调用上述4个方法,每个调用之间休眠1秒,运行时间单位是毫秒(ms)
解法5(linux uniq):
利用LInux命令, 如下所示:
$ cat uniq_test.txt
3
4
5
2
3
4
5
$ sort uniq_test.txt | uniq -u
2
同样测试在1,000,001行的文件中寻找唯一值时的花费,
$ cat find_uniq_value_test.txt | wc -l
1000001
$ time sort find_uniq_value_test.txt | uniq -u
1000001
real 0m2.907s
user 0m9.426s
sys 0m0.039s
需要2秒多.
补充:
构造一个满足要求的测试文本的shell命令
$ seq 1 2 10
1
3
5
7
9
$ seq 1 2 10 > temp.txt
$ seq 1 2 10 >> temp.txt
$ echo 11 >> temp.txt
$ cat temp.txt
1
3
5
7
9
1
3
5
7
9
11
$ shuf temp.txt
7
3
5
11
1
1
5
9
7
9
3
$ shuf temp.txt > temp_shuf.txt
$ sort -n temp_shuf.txt | uniq -u
11
参考了:
http://x-wei.github.io/%E6%89%93%E4%B9%B1%E6%96%87%E6%9C%AC%E7%9A%84%E8%A1%8C.html