力扣:查找只出现一次的数字,java实现

目录

 

题目:

1、简单粗暴法

2、List集合方法

3、哈希表方法

4、异或法(最优)


题目:

难度:简单

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

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

官方给出的解题代码是python的,这里用的编程语言是java。

我总结的解题方法,一共有四种。分别是简单粗暴方法、List集合方法、哈希表方法和异或法。

话不多说,看代码。

1、简单粗暴法

//简单粗暴法
	private int method1(int[] arr) {	
		out:for(int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length;j++) {
				if(arr[i]==arr[j]&&i!=j) {
					continue out;
				}
			}
				return arr[i];
		}
		throw new IllegalArgumentException("No single numble");
	}
	

 该方法利用两个循环,遍历整个数组来求解。第一个循环从第一个数组元素开始,然后通过第二个循环也从数组的第一个元素遍历来比较数组里是否有元素和自身相等。在第二个循环里比较,如果第一个循环的元素和第二个循环的元素相等,    并且不是自身和自身比较即(i != j),那么第一个循环的元素就不用再继续通过第二个循环比较来查找了,随即结束第一个循环的本次循环。如果第一个循环的元素与第二个循环的元素逐一比较,一直没有相等的,表明这就是我们要找的只存在一次的数,就返回当前的元素。如果第一个循环完毕,也就是数组里所有的元素都遍历过之后,依然没有找到我们要找的数,说明数组里的元素存在的次数都大于一次,此时抛出参数异常。

该方法做了很多无用功,显然最好的地方就是简单容易想到。时间复杂度为n平方

2、List集合方法

public int method2(int []nums) {
			List<Integer> list = new LinkedList<>();
			for(int i=0;i<nums.length;i++) {
				if(!list.contains(nums[i])) {
					list.add(nums[i]);
				}else {
					list.remove((Object)nums[i]);
				}
			}
			return list.get(0);
	}
	

 用一个循环,遍历数组。从数组的第一个元素开始遍历,如果list集合包含有当前元素,就将该元素从集合中删除掉,如果没有,就将该元素添加到数组中。这样,到最后,就会剩下只出现了一次的元素。返回该集合第一个元素即使我们所求的数了。

这个方法明显比简单粗暴方法效率提升了不少,时间复杂度为n。

3、哈希表方法

public int method3(int []nums) {
			Map<Integer,Integer> map = new HashMap<>();
			for(int i=0;i<nums.length;i++) {
				if(map.containsKey(nums[i])) {
					map.remove(nums[i]);
				}else {
					map.put(nums[i], null);
				}
			}
			return map.keySet().iterator().next();
	}

该方法的中心思想和List集合方法的中心思想差不多,如果理解了第二种方法,相信这种方法你一下子就能理解。

该方法利用Hash表来存储遍历的元素。利用一个循环来遍历目标查询数组,如果当前元素在mp里面存在,就删除该元素,如果没有,就添加。最后遍历完目标查询数组,返回map里的元素。与第二种方法不同的地方,就是添加的方法和遍历集合的方法。在这里是将元素当成key添加到map中的,value设置为null。

时间复杂度为n。

4、异或法(最优)

//异或法(最优)
	public int method4(int []nums) {		
			int ans = nums[0];
			for(int i=1;i<nums.length;i++) {
				ans = ans^nums[i];
			}
			return ans;
	}

 该方法运用了异或的思想。异或的意思,就是两个数相同为0,不同为1。满足交换律,也就是所有的数异或,不论两个相同的数是否先后进行异或运算,最后都等于0。

首先声明一个变量ans等于数组的第一个元素,然后运用一个循环遍历数组剩下的元素,每一个元素逐一与ans进行异或运算,最后得到的ans就是我们要求的数。

有些朋友可能在想,说的两个数相同为0,不同为1呀,为什么就会求得目标只出现一次的数了呢?因为两个数相同为0,不同为1指的是二进制,计算机是二进制进行异或运算的,最后又转换为十进制给我们,所以我们得到了只出现一次的数。为什么说这个问题,因为我这木头脑袋想过,如果你也是木头脑袋,正好给你解惑,如果不是,尽情在心里夸一下自己,你真是个小机灵鬼。

该方法时间复杂度为n。

本篇完

发布了38 篇原创文章 · 获赞 9 · 访问量 1449

猜你喜欢

转载自blog.csdn.net/qq_42023080/article/details/105586002
今日推荐