在Java中查找N个列表之间的公共元素

在Java中查找N个列表之间的公共元素,java,arrays,list,collections,intersection,Java,Arrays,List,Collections,Intersection,我需要编写一个Java程序来查找任意数量的列表或整数数组(任意长度)的交集(公共元素)。我想Java列表可能有一个有用的方法来实现这一点,但我正在查看API,却找不到它 有什么提示吗?您可以尝试使用此方法查找交叉点/公共点- public <T> List<T> common(List<T> list1, List<T> list2) { List<T> commonList = new ArrayList<T&g

我需要编写一个Java程序来查找任意数量的列表或整数数组(任意长度)的交集(公共元素)。我想Java列表可能有一个有用的方法来实现这一点,但我正在查看API,却找不到它


有什么提示吗?

您可以尝试使用此方法查找交叉点/公共点-

public <T> List<T> common(List<T> list1, List<T> list2) {
        List<T> commonList = new ArrayList<T>();

        for (T t : list1) {
            if(list2.contains(t)) {
                list.add(t);
            }
        }


        return commonList;
    }

通过将一个列表的元素复制到一个新列表中,并使用
retainal
,可以找到两个列表之间的公共元素:

List<T> commonElements = new ArrayList<>(list1);
commonElements.retainAll(list2);
e、 g


列出公共元素(Iterable您可以使用
retainal()
方法,它是Java
集合的一部分
类:

List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
System.out.println("First list has elements: " + list1);

List<Integer> list2 = new ArrayList<Integer>();
list2.add(2);
list2.add(3);
list2.add(4);
System.out.println("Second list has elements: " + list2);

list1.retainAll(list2);
System.out.println("Intersection between the lists is: " + list1);
在使用
retainal
removeAll
containsAll
ArrayList
s的任何方法之前,您应该仔细考虑,因为
contains
对于
ArrayList
具有
O(n)
时间复杂度。如果
a
b
都是
ArrayList
s长度
n
a.retainal(b)
具有时间复杂度
O(n^2)
。如果在循环中使用
a.retainal(b)
,生成的算法很快就会变得完全不切实际

另一种解决方案是将
ArrayList
s转换为
HashSet
s。
包含
,因为
HashSet
具有
O(1)
时间复杂度

static <T> List<T> commonElements(Iterable<? extends List<? extends T>> lists) {
    Iterator<? extends List<? extends T>> it = lists.iterator();
    Set<T> commonElements = new HashSet<>(it.next());
    while (it.hasNext())
        commonElements.retainAll(new HashSet<>(it.next()));
    return new ArrayList<>(commonElements);
}
您可以按如下方式进行测试

List<Integer> list1 = Arrays.asList(1, 1, 2, 2, 2, 3, 4);
List<Integer> list2 = Arrays.asList(1, 1, 1, 2, 2, 3, 5);
List<Integer> common = commonElements(Arrays.asList(list1, list2));
System.out.println(common);

有许多方法可以改进上述方法。例如,您可以首先处理最小的
列表
,以使
多重性
尽可能小。同样,在计算
列表计数
后,如果
列表计数
较小,您可以交换
列表计数
多重性
。您也可以可以将
while
替换为
while(!multiplicities.isEmpty()&&iterator.hasNext())
这样,一旦发现交叉点为空,算法就会立即停止。

您正在寻找
retainAll
。谢谢@Tunaki,我能问一下伪代码是什么吗?这个方法需要两个列表,而不是任意数量的列表。谢谢Andy,我只是问一个问题,“T”是什么在您的方法中?它是一个类型变量。添加。
T
是一个泛型(任意)type.if
lists
为空,它将使用java.util.NoSuchElementException失败。确实会:我认为应该使用异常来指示未定义的条件。但是,如果需要,您可以简单地更改它以返回空列表。已编辑。
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
System.out.println("First list has elements: " + list1);

List<Integer> list2 = new ArrayList<Integer>();
list2.add(2);
list2.add(3);
list2.add(4);
System.out.println("Second list has elements: " + list2);

list1.retainAll(list2);
System.out.println("Intersection between the lists is: " + list1);
First list has elements: [1, 2, 3]
Second list has elements: [2, 3, 4]
Intersection between the lists is: [2, 3]
static <T> List<T> commonElements(Iterable<? extends List<? extends T>> lists) {
    Iterator<? extends List<? extends T>> it = lists.iterator();
    Set<T> commonElements = new HashSet<>(it.next());
    while (it.hasNext())
        commonElements.retainAll(new HashSet<>(it.next()));
    return new ArrayList<>(commonElements);
}
static <T> List<T> commonElements(Iterable<? extends List<? extends T>> lists) {
    Iterator<? extends List<? extends T>> iterator = lists.iterator();
    Map<T, Integer> multiplicities = count(iterator.next());
    while (iterator.hasNext()) {
        Map<T, Integer> listCount = count(iterator.next());
        for (Iterator<Map.Entry<T, Integer>> it = multiplicities.entrySet().iterator(); it.hasNext();) {
            Map.Entry<T, Integer> e = it.next();
            T key = e.getKey();
            Integer count = listCount.get(key);
            if (count == null)
                it.remove();
            else
                e.setValue(Math.min(count, e.getValue()));
        }
    }
    List<T> result = new ArrayList<>();
    for (Map.Entry<T, Integer> e : multiplicities.entrySet())
        result.addAll(Collections.nCopies(e.getValue(), e.getKey()));
    return result;
}

private static <T> Map<T, Integer> count(List<? extends T> list) {
    Map<T, Integer> result = new HashMap<>();
    for (T t : list)
        result.merge(t, 1, Integer::sum);
    return result;
}
List<Integer> list1 = Arrays.asList(1, 1, 2, 2, 2, 3, 4);
List<Integer> list2 = Arrays.asList(1, 1, 1, 2, 2, 3, 5);
List<Integer> common = commonElements(Arrays.asList(list1, list2));
System.out.println(common);
[1, 1, 2, 2, 3]