【题目】
给一个数组arr,其中只有一个数出现了奇数次,其它数出现了偶数次,打印这个数。
【输入】
输出包含两行,第一行包含一个整数n(1 \leq n \leq 10^5)(1≤n≤105),代表数组arr长度,第二行有n个数,代表数组arrarr_i 为32位整数arri为32位整数。输出包含两行,第一行包含一个整数n(1 \leq n \leq 10^5)(1≤n≤105),代表数组arr长度,第二行有n个数,代表数组arrarr_i 为32位整数arri为32位整数。
【输出】
输出一个整数,代表出现次数为奇数次的那个数。
【示例】
输入:5
3 1 3 1 2
输出:2
【复杂度】
时间复杂度O(n),额外空间复杂度O(1)。
【代码】
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int count = sc.nextInt();
int res = 0;
//每次将输入的值进行异或运算
for(int i=0;i<count;i++){
int tmp = sc.nextInt();
res ^= tmp;
}
System.out.println(res);
}
}
进阶:数组中存在两个出现奇数次的数
【题目】
给定一个数字arr,其中只有两个数字出现了奇数次,其它数字都出现了偶数次,按照从小到大顺序输出这两个数。
【输入】
第一行输入一个n,第二行输入n个数
【输出】
输出出现奇数次的两个数,按照从小到大的顺序。
【示例】
输入 4
1 1 2 3
输出
2 3
【分析】
-
先把数组中所有数全部异或运算,得到的结果为两个所求数ab的异或值
-
由于ab异或的值不为0(因为如果为0,那么意味着ab相等),所以ab的二进制位中必然存在一个不相等的位,对ab两个数进行异或运算时,这个位上的运算结果为1,所以要先找到ab异或结果中为1的位置(找到一位即可),那么我们找最右侧的1
寻找的方法是:把ab异或后的结果eor取反后加1,然后与eor进行并运算(rightOne的结果如:(00000100)
int rightOne = eor & (~eor +1);
-
筛选出所有在该位置上不为1的数进行异或运算(这样做的目的是把a和b分开,进行异或运算得到其中一个数)
if((cur & rightOne) == 0) //筛选出所有在该位置上不为1的数进行异或 if((cur & rightOne) == rightOne) //筛选出所有在该位置上为1的数进行异或
-
这样,有了a和b的异或值,有了a或b的值,那么将eor和neweor异或就能得到另一个值
【代码】
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int count = sc.nextInt();
int[] arr = new int[count];
int total = 0;
//求出总体的异或和
for(int i=0; i<count; i++){
arr[i] = sc.nextInt();
total ^= arr[i];
}
//取出异或和的最右侧的‘1’位
total = total & (~total + 1);
int even = 0;
int odd = 0;
for(int i=0; i<count; i++){
//‘1’位上为0的数进行异或和
if((arr[i]&total) == 0){
even ^= arr[i];
}
//‘1’位上位1的数异或求和
else{
odd ^= arr[i];
}
}
int[] res = new int[2];
res[0] = even<odd?even:odd;
res[1] = even+odd-res[0];
System.out.println(res[0]+" "+res[1]);
}
}