翻看博客的时候看到了这道题,据说是阿里的一次面试题
大佬的想法也很巧妙,我在这里又总结了一下
题目一:在n个整数中,仅有1个整数出现1次,其余的整数都出现了偶数次,求这个仅出现1次的整数。要求时空复杂度尽可能低。
这道题很简单,有经验的一看就知道作异或运算
public static int getNum(int[] a){
int n = a.length;
int result = 0;
for(int i = 0; i < n; i++)
{
result ^= a[i];
//a^b^b=a,
// 3 ^ 4 ^ 6 ^ 5 ^ 5 ^ 6 ^ 4
//=3 ^ (4 ^ 4) ^ (5 ^ 5) ^ (6 ^ 6)
//=3 ^ 0 ^ 0 ^ 0
//=3
}
return result;
}
异或运算:
a^b^b=a
=3 ^ 4 ^ 6 ^ 5 ^ 5 ^ 6 ^ 4
=3 ^ (4 ^ 4) ^ (5 ^ 5) ^ (6 ^ 6)
=3 ^ 0 ^ 0 ^ 0
=3
题目二:在n个整数中,有1个奇数仅出现一次,有1个偶数仅出现一次,其余的整数都出现了偶数次,求奇数和偶数的值。要求时空复杂度尽可能低。
结合题目一的经验,我们只需要将偶数和奇数分开处理就可以了,很简单
public static void getNums1(int[] a){
int n = a.length;
int result1 = 0;
int result2 = 0;
for(int i = 0; i < n; i++)
{//分开奇偶处理就好了
if(a[i]%2 == 0){//偶数
result1 ^= a[i];
}else {//奇数
result2 ^=a[i];
}
}
System.out.println(result1);
System.out.println(result2);
}
题目三:在n个整数中,有2个不同的整数分别出现1次,其余的整数都出现了偶数次,求仅出现1次的2个整数。要求时空复杂度尽可能低。
这道题就比较难了,像是第一题提升难度版,一个数组变成的两个
思路:
我们可以按照题目以的方法取出这两个唯一数的异或运算结果
然后就是想办法怎么将这个运算结果分解开变成原本的两个数字
这里举个例子:假设一个数组是{7, 1, 5, 14, 8, 8, 5, 14}
可以看到结果应该是7和1,
7的二进制表示:0111
3的二进制表示:0001
二者异或结果的二进制:0110
由于3和7不同,所以它们的二进制数中,必然存在不同的位。根据这个特征可以找出异或结果的第一个1出现在哪一位(从右往左看),而且异或完的结果必然大于小的唯一数,小于大的唯一数,
我们根据这个想法可以得到特定标志位的数字:flag=0010,(大数的这一位置必然为1)
遍历数组中这个标志位有数字的元素:
就是7^8^8^14^14=7,就求得了其中一个数字,另一个数字想必大家都会了
public static void getNums2(int[] a){
int n = a.length;
int result = getXOR(a);
int flag = getFlag(result);
int ans1=0;
int ans2=0;
for (int i = 0; i < n; i++)
{
if ((flag & a[i])>0)
{
ans1 ^= a[i];
}
}
ans2 = ans1 ^ result;
System.out.println(ans1);
System.out.println(ans2);
}
public static int getXOR(int[] a){
int n = a.length;
int result = 0;
for(int i = 0; i < n; i++)
{
result ^= a[i];
}
return result;
}
public static int getFlag(int xor){
int flag = 1;
while((flag & xor) == 0)
{
flag <<= 1;
}
return flag;
}