Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
解法一:
public class Solution {
public int singleNumber(int[] A) {
HashSet<Integer> set=new HashSet<Integer>();
for(int i:A)
{
if(set.contains(i))
set.remove(i);
else
set.add(i);
}
Iterator<Integer> itr=set.iterator();
return itr.next();
}
}
利用哈希表,如果已经存在就移除,否则加入,最后只剩1个单独存在的元素
解法二:
public class Solution {
public int singleNumber(int[] A) {
int a=0;
for(int i:A)
a^=i;
return a;
}
}
0异或任何数都是任何数
任何数异或本身都是0
异或存在交换律
所以所有存在偶数个的数异或完结果都为0,剩下的为只出现一次的数
扩展:
1.一个数组中有两个元素只出现一次,其他所有元素都出现两次,求这两个只出现一次的元素
哈希表解法依旧有效,看解法二。
依旧所有元素求异或,其结果为两个只出现一次的元素不同的位为1,相同的位为0
找到某个不同的位flag。
再次遍历,任意元素&flag会分成两个集合,每个集合一个只出现一次的元素。剩下思路同原题。
package SingleNumber;
public class Solution2
{
public static void singleNumber(int[] A)
{
int a = 0;
for (int i : A)
a ^= i;
int flag = 1;
while ((a & flag) == 0)
flag <<= 1;
int result1 = 0;
int result2 = 0;
for (int i : A) {
if ((i & flag) == 0)
result1 ^= i;
else
result2 ^= i;
}
System.out.println(result1 + " " + result2);
}
public static void main(String[] args)
{
int[] a = { 1, 2, 3, 67, 43, 23, 2, 3, 1, 67, 43, 55 };
singleNumber(a);
}
}
扩展2:
一个数组中有一个元素只出现1次,其他所有元素都出现k次,求这个只出现1次的元素
(1)K为偶数,解法同原题
(2)K为奇数
将每个数字转化为二进制,每一位相加模上K。再将得到的二进制转为十进制,即为只出现一次的数。(注意不能用十进制,十进制每一位都有可能本身大于3)
public class Solution4
{
private static int[] res;
public static int singleNumber(int[] A, int k)
{
int m = 0;
res = new int[100];
for (int i : A)
foo(i);
int j = 1;
for (int i = 1; i <= res[0]; i++, j <<= 1) {
m += res[i] % k * j;
}
return m;
}
public static void foo(int a)
{
int i = 1;
while (a != 0) {
if ((a & 1) == 1)
res[i] += 1;
a >>= 1;
i++;
}
if (res[0] < i - 1)
res[0] = i - 1;
}
public static void main(String[] args)
{
int[] a = { 1, 1, 1, 2, 2, 2, 45, 45, 45, 88, 99, 99, 99, 355, 666,
666, 355, 355, 666 };
System.out.println(singleNumber(a, 3));
}
}