在Java中查找N个列表之间的公共元素
我需要编写一个Java程序来查找任意数量的列表或整数数组(任意长度)的交集(公共元素)。我想Java列表可能有一个有用的方法来实现这一点,但我正在查看API,却找不到它在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
有什么提示吗?您可以尝试使用此方法查找交叉点/公共点-
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.iflists
为空,它将使用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]