Java容器使用:Set

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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值