1.题目说明
输入一个数组和一个数字 s�,在数组中查找两个数,使得它们的和正好是 s�。
如果有多对数字的和等于 s�,输出任意一对即可。
你可以认为每组输入中都至少含有一组满足条件的输出。
数据范围
数组长度 [1,1002]。
样例
输入:[1,2,3,4] , sum=7 输出:[3,4]
2.代码实现
原本代码
class Solution {
public int[] findNumbersWithSum(int[] nums, int target) {
HashSet<Integer> a = new HashSet<>();
int x1 = 0,x2 = 0;
for(int x:nums)
a.add(x);
for(int x:a) {
int temp = x;
a.remove(x);
if(a.contains(target - temp)){
x1 = temp;
x2 = target - temp;
break;
}
}
int[] res = new int[2];
res[0] = x1;
res[1] = x2;
return res;
}
}
运行结果
代码运行状态: Non Zero Exit Code ×
输入:
1 2 3 4
7
输出: Non Zero Exit Code
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
at Solution.findNumbersWithSum(Line:8)
at Main.main(Line:351)
改进之后
import java.util.HashSet;
import java.util.Iterator;
class Solution {
public int[] findNumbersWithSum(int[] nums, int target) {
HashSet<Integer> a = new HashSet<>();
int x1 = 0,x2 = 0;
for(int x:nums)
a.add(x);
Iterator<Integer> temp = a.iterator();
while(temp.hasNext()){
Integer x = temp.next();
temp.remove();
if(a.contains(target - x)){
x1 = x;
x2 = target - x;
break;
}
}
int[] res = new int[2];
res[0] = x1;
res[1] = x2;
return res;
}
}
代码提交Accepted
3.错误分析
在原本代码中,我们使用了增强的for循环对a(set)里的所有元素进行遍历,可是,为了保证测试用例可能会有target = 8,而数组元素里只有1个4这样的情况出现,即一个元素被查到两次都会是true。我们必须在遍历到这个元素时,记录下这个元素的值,并把它从set里删掉,再进行对(target - 元素)的contains查询,这样才能保证输出结果在遇到上述情况时,也是正确的。
但是使用增强的for循环遍历的话,相当于在遍历set时删掉了set的元素,这会导致ConcurrentModificationException异常,这也是原本代码出错的原因。
那么如果想对set进行边遍历边修改元素的话,使用迭代器iterator可以满足这个要求,不会出现异常。实现代码如改进之后。
4.对于Set的理解
如果说把Set这种容器对应到数学中的概念的话,最匹配的无疑是集合。也就是说Set就是包含同种类型数据的一个集合。HashSet是无序的,而TreeSet是有序的。但又与普通集合不同,Set里当然是可以存相同元素的。
能用到Set的地方自然是在数据集里寻找目标元素,就像集合里是否包含一些元素一样,例如本题,寻找数组中和为s的组,那么所需寻找的目标元素就是(s-set(x))。未来或许会遇到更多的题里会用到set,这里仅是举例。
使用set的原因是它的查询元素时间复杂度(即contains函数)为o(1),极小,放在上面的题里,查找两个指定元素和为s的复杂度即为o(n),n为set中的元素个数,这能够极大减小查询的时间复杂度。
5.Set的一些常用函数
接口:java.util.Set<K>
实现:
- java.util.HashSet<K>:哈希表
- java.util.TreeSet<K>:平衡树
函数:
add():添加元素
contains():是否包含某个元素
remove():删除元素
size():返回元素数
isEmpty():是否为空
clear():清空
java.util.TreeSet多的函数:
ceiling(key):返回大于等于key的最小元素,不存在则返回null
floor(key):返回小于等于key的最大元素,不存在则返回null