找出数组中只出现了一次的数字(Java)

题目

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个 元素均出现两次。找出那个只出现了一次的元素。

  • 示例
    • 示例1:
      输入:[2,2,1] 输出:1
    • 示例2:
      输入:[4,1,2,1,2] 输出:4

题目分析

注意输入格式,在主方法中不能直接得到数组,应先定义字符串变量接收键盘输入,在使用String类的几种方法得到这个整数数组。
另外定义一个方法找只出现了一次的元素,这个方法返回值为int类型。在方法中,要找到那个元素,有以下解决方法:

方法1

最基本的方法就是双重循环遍历数组,可以直接找出只出现了一次的数,但是,显然这种方法时间复杂度高,效率低下

方法2

使用Set集合存储,Set集合不存储重复值,add()方法返回值为boolean类型,这一特点可以利用。
Set集合的add方法,添加成功返回true,否则返回false,而Set集合不存储重复值,所以当要添加的数与集合中已存在的数重复时,不会再进行添加操作,返回false,这时再进行remove操作,将集合中已存在的那个与要添加的数相同的元素移除,这样将作为方法参数传递过来的整型数组遍历完后,到最后集合中就只剩下了那个只出现了一次的数字。

方法3

使用异或运算符^,0与其他数字异或的结果是那个数字,相等的数字异或得0。要操作的数组中除了某个数字只出现了一次之外,其他数字都出现了两次,所以可以定义一个变量赋初始值为0,用这个变量与数组中每个数字做异或运算,并将这个变量值更新为那个运算结果,直到数组遍历完毕,最后得到的变量的值就是数组中只出现了一次的数字了。这种方法只需遍历一次数组,提高了程序运行的效率。

总结一下:这种解法要用到异或运算的几个规则:

  1. 0^0 = 0;
  2. 0^a = a;
  3. a^a = 0;
  4. a ^ b ^ a = b.

当然这些只是一部分,不过刚好够用,想要了解异或运算符的小伙伴可以去看看百度百科的介绍:异或运算

代码实现

主方法

public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		str = str.substring(1, str.length()-1);//去掉键盘输入的字符串中的"["和"]"
		String[] s = str.split(",");//将字符串以","分割,转为一个字符串数组
		int[] arr = new int[s.length];//定义一个整形数组,准备用来存数据了
		for(int i = 0; i < arr.length; i++)
			arr[i] = Integer.parseInt(s[i]);//将字符串转为int类型数据存入整型数组中
		System.out.println(Find_Num(arr));//调方法
	}

注:这里直接将字符串转为整型数据使用的是包装类Integer类的parseInt()静态方法,调用时直接类名调用,方法返回值为Integer类型,但是可以自动拆箱为int型,因此用int或Integer类型接收均可。
另外,注意一下主方法中没有对方法返回值进行判断而直接做了输出,也就是说不考虑那个数字不出现的情况

方法1

第一种:使用计数器的

public static Integer Find_Num_1(int[] arr){
		for(int i = 0; i < arr.length; i++) {
			int count = 1;//计数器
			for(int j = 0; j < arr.length; j++) {
				if(i == j)
					continue;//下标相等则直接进入下一次循环
				if(arr[i] == arr[j])
					count++;//如果不同下标的数组元素相等,则计数器加1
			}
			if(count == 1)
				return arr[i];//返回只出现了一次的元素
		}
		return null;//找不到则返回null
	}

第二种:不使用计数器

public static Integer Find_Num_1(int[] arr){
		for(int i = 0; i < arr.length; i++){
			for(int j = 0; j <= arr.length; j++){
			//注意循环结束的条件,实际运行时j不会超出数组范围
				if(i == j)
					continue;
				if(j == arr.length)
				//因为这里的判断,让代码运行时在超出范围前就结束了循环
					return arr[i];
				if(arr[i] == arr[j])
					break;
			}
		}
		return null;//找不到则返回null
	}

可能已经有人注意到,方法1中两段代码方法的返回值为Integer类型,这样就方便了在没有找到时返回null作为标志

方法2

public static int Find_Num_2(int[] arr) {
		Set<Integer> set = new HashSet<Integer>();//创建Set集合
		for(int i : arr) {//增强for循环遍历数组
			if(!set.add(i))//添加不成功返回false,前加上!运算符变为true
				set.remove(i);//移除集合中与这个要添加的数重复的元素
		}
		return set.toArray(new Integer[set.size()])[0];
		//返回它转为Integer数组后数组的第一个元素
	}

使用时要注意前提,必须存在那个只出现了一次的数字,否则Set集合长度将为0,最后一句代码运行时出错,改进一下的话,就像方法1那样,将返回值类型设置为Integer:

public static Integer Find_Num_2(int[] arr) {
		Set<Integer> set = new HashSet<Integer>();//创建Set集合
		for(int i : arr) {//增强for循环遍历数组
			if(!set.add(i))//添加不成功返回false,前加上!运算符变为true
				set.remove(i);//移除集合中与这个要添加的数重复的元素
		}
		if(set.size() == 0)	return null;
		//如果Set集合长度为0,返回null表示没找到
		return set.toArray(new Integer[set.size()])[0];
	}

方法3

public static int Find_Num_3(int[] arr) {
		int flag = 0;
		for(int i : arr) {
			flag ^= i;
		}
		return flag;
	}

这段代码的问题在于,如果用户输入了偶数个数的数据,方法将返回0值,而当这个只出现了一次的数字为0时,方法当然也返回0,所以使用前提是必须存在一个只出现了一次的数字

总结

需要注意的是: 这个题的前提条件是这个只出现了一次的数字是存在的,那么使用时在输入阶段需要用户注意到这个问题,输入的数据个数只能是奇数,否则在使用方法3时会出现答案错误的情况,而方法1和改进后的方法2可以正常使用,如果输出为null代表着没有找到。

  • 11
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值