俩个数出现了奇数次
上一篇博客一个数出现了奇数次
牛客网链接
:题的内容:给定一个数组arr,其中只有两个数字出现了奇数次,其它数字都出现了偶数次,按照从小到大顺序输出这两个数。
输入描述:
第一行输入一个n,
第二行输入n个数
输出描述
输出出现奇数次的两个数,按照从小到大的顺序。
示例1
输入:
4
1 1 2 3
输出:
2 3
示例2
输入:
6
11 22 11 23 23 45
输出:
22 45
代码实现
方法一:采用的是HashSet
思路:直接遍历数组,将值加入到HashSet当中,如果第一次加入,set当中还没有值,就直接加入,当第二次进来的时候,将第一次进来的直接踢出去,这样循环完成之后,set当中只剩下了需要的结果。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (scan.hasNext()){
//用set实现,找出出现次数为奇数次的那俩个数字
Set<Integer> set = new HashSet<>();
int n = scan.nextInt();
int[] arr = new int[n];
for (int i = 0;i < n;i++){
arr[i] = scan.nextInt();
if (!set.contains(arr[i])){
set.add(arr[i]);
}else{
//如果存在把之前加进来的踢出去,因为它出现了奇数次,就和最后的结果没有什么关系了
set.remove(arr[i]);
}
}
//到达这里,set里面就只剩下俩个出现奇数次的数字了
//得到这俩个数字
//第一种获取值的方法
int[] res = new int[2];
int k = 0;
for (int i = 0;i < n;i++){
if (set.contains(arr[i])){
set.remove(arr[i]);
res[k++] = arr[i];
if (k == 2)break;
}
}
//第二种获取值的方法,采用迭代器
/*int[] res = new int[2];
int k = 0;
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
res[k++] = it.next();
}*/
if(res[0] < res[1]){
System.out.println(res[0]+" "+res[1]);
}else{
System.out.println(res[1]+" "+res[0]);
}
}
}
}
方法二:采用位运算的方法
思路:首先之前的数组中只有一个出现奇数次的数字,采用的是异或的方法(具体方法,看我上一篇博客,上面有链接),同样俩个奇数次也可以异或,如果想办法可以将这俩个数分到俩个组里面,是不是这样一组里面就有一个数字,就跟之前的做法一致了。
因此最主要的是如何分组:分组,肯定是要找不同之处,首先我们同样遍历数组进行异或,最后面得到的结果是那俩个数字的异或结果,比如这俩个数字是3和5,他们的二进制是011和101,那么它俩异或的结果是010,那么观察3和5的二进制,那么它俩倒数第二位一个是0一个是1,他们异或的结果正好这个不同的位置是1,因此我们只有确定这个1的位置,就可以进行分组了,接下来看代码,代码中注解和详细。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (scan.hasNext()){
int n = scan.nextInt();
int[] arr = new int[n];
//用于存储2个出现奇数次的整数
int result[] = new int[2];
//1.第1次进行整体异或运算
int res = 0;
for (int i = 0;i < n;i++){
arr[i] = scan.nextInt();
res ^= arr[i];
}
// //如果进行异或运算的结果为0,则说明输入的数组不符合题目要求
// if (res == 0){
// return null;
// }
//2.确定2个整数的不同位,以此来作为分组依据
int separator = 1;
while ((res & separator) == 0){
separator <<= 1;//进行左移
}
//3.第二次分组进行异或运算
for (int i = 0;i < arr.length;i++){
if ((arr[i] & separator) == 0){
result[0] ^= arr[i];
}else{
result[1] ^= arr[i];
}
}
if(result[0] < result[1]){
System.out.println(result[0]+" "+result[1]);
}else{
System.out.println(result[1]+" "+result[0]);
}
}
}
}