Java,找到两个数组的交集

Posted

技术标签:

【中文标题】Java,找到两个数组的交集【英文标题】:Java, find intersection of two arrays 【发布时间】:2013-07-25 15:48:55 【问题描述】:

我已经阅读了其他一些堆栈溢出线程:

to find the intersection of two multisets in java

How do I get the intersection between two arrays as a new array?

public static int[] intersection (int [] x, int numELementsInX, int [] y, int numElementsInY) 

我正在尝试检查两个数组以及它们的元素数量(numElementsInX 和 numElementsInY),并返回一个包含数组 x 和 y 的公共值的新数组。他们的交汇点。

Example,if x is1,3,5,7,9and y is9,3,9,4 then
intersection(x, 5, y, 4 should return 3, 9 or 9, 3

我已阅读我需要使用 LCS 算法。谁能给我一个例子来说明如何做到这一点?数组和数组中的值都在另一个方法中初始化和生成,然后传入交集。

感谢任何帮助/澄清。

编辑代码

for (int i=0; i<numElementsInX; i++)
    for (int j=0; j<numElementsInY; j++)
        if (x[j]==x[i])  //how to push to new array?; 
        
        else
        
    

【问题讨论】:

您已经有 2 个问题可以解决这个问题。你试过什么? 不需要额外的numELementsInX参数,直接使用x.length即可。 我使用额外的参数,因为用户可以输入任意数量的条目,最多 100 个,两个数组可能有不同数量的值。我们的教授希望我们将数组初始化为 100,然后跟踪用户输入。这就是我不使用它的原因。 LCS 算法对这个问题没有用处 仅用于字符串吗? 【参考方案1】:

最简单的解决方案是使用集合,只要您不关心结果中的元素会有不同的顺序,并且重复项会被删除。输入数组array1array2 是给定int[] 数组的Integer[] 子数组,对应于您打算处理的元素数量:

Set<Integer> s1 = new HashSet<Integer>(Arrays.asList(array1));
Set<Integer> s2 = new HashSet<Integer>(Arrays.asList(array2));
s1.retainAll(s2);

Integer[] result = s1.toArray(new Integer[s1.size()]);

上面将返回一个Integer[],如果需要,可以很简单地将其内容复制并转换为int[]

【讨论】:

你能举个例子吗?我会谷歌。我的教授还没有教我们套路。 你必须提到array1array2这里需要Integer[]才能正常工作,它不适用于int[] 此外,这不会保留重复项——即使array1array2 都多次出现x,这也不会保留这些重复项。 好的,两个警告都提到了。谢谢,伙计们! s2 不需要是一个集合,因此您可以删除 new HashSet 构造函数调用并将其保留为 Collection - 可能会稍微提高性能。【参考方案2】:

如果您不想使用其他数据结构(例如 Set),那么基本想法是您希望遍历其中一个数组的元素,并为每个值查看它是否出现在另一个数组中。你怎么看它是否出现在另一个数组中?遍历另一个数组中的元素,并查看每个元素的值是否等于您要查找的值。如果您上课的目标是学习如何写好 Java,我怀疑您最好自己尝试解决这个问题您所写的,以便您可以获得更详细的反馈和正确方向的指示。

【讨论】:

用嵌套的 for 循环更新,有点像我试图采取的方向。谢谢! 您可以使用 Ruchira 的答案中的方法(推入列表或集合),然后在返回之前转换为数组,否则您需要将数组和变量保存在您存储的位置数组中的下一个空白点(从 0 开始)。当您找到匹配项时,将其放入数组中的下一个空白点,然后递增。不确定这是否是你的课程教给你的,但它应该可以工作(除了处理重复,这是一个额外的复杂性)。【参考方案3】:

试试这个:

public static void main(String[] args) 
    int[] arr1 = new int[]1, 2, 3, 4, 5;
    int[] arr2 = new int[]3, 2, 5, 9, 11;
    getIntersection(arr1, arr2);


public static Object[] getIntersection(int[] arr1, int[] arr2) 
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < arr1.length; i++) 
        for (int j = 0; j < arr2.length; j++) 
            if (arr1[i] == arr2[j]) 
                list.add(arr1[i]);
            
        
    
    return list.toArray();

【讨论】:

优雅,它用 632,698/1,000,000 个相交占用了我的 4GB 堆空间。我认为这可能比带有小数组且没有装箱的 HashSet 更快。【参考方案4】:

如果您对java-8 满意,那么我能想到的最简单的解决方案是使用流和过滤器。一个实现如下:

public static int[] intersection(int[] a, int[] b) 
    return Arrays.stream(a)
                 .distinct()
                 .filter(x -> Arrays.stream(b).anyMatch(y -> y == x))
                 .toArray();

【讨论】:

这是不正确的。考虑这种情况:a = [1,2,2,1] b = [2] 答案应该是 [2],但这给出的答案是 [2,2] 还是不行。取 a = [1,2,2,1] 和 b = [2,2]。答案应该是 [2,2] 但这给出的答案是 [2] @UjjwalGulecha 据我所知,您要么关心重复,要么不关心。你能详细说明一下吗?不确定我是否遗漏了什么。 非虚拟机。 OP问的是你的答案是什么。我一直在寻找基本上允许重复的交集,即如果 A 有 n 个 x,B 有 n-1 个 x,它们的交集应该有 n-1 个 x。 看起来这不适用于Object-type like String,因为toArray() 将返回Object[]【参考方案5】:

数组中的重复元素查找交集。

    int [] arr1 = 1,2,2,2,2,2,2,3,6,6,6,6,6,6,;
    int [] arr2 = 7,5,3,6,6,2,2,3,6,6,6,6,6,6,6,6,;

    Arrays.sort(arr1);
    Arrays.sort(arr2);
    ArrayList result = new ArrayList<>();
    int i =0 ;
    int j =0;
    while(i< arr1.length && j<arr2.length)
    if (arr1[i]>arr2[j])
        j++;

    else if (arr1[i]<arr2[j])
        i++;

    else 
        result.add(arr1[i]);
        i++;
        j++;
    
    
    System.out.println(result);

【讨论】:

请为您的答案添加解释。基本上解释它为什么起作用【参考方案6】:

使用哈希映射查找交叉点包括重复项。

输出:1 2 2 15 9 7 12

public static void main(String[] args) 
    int[] arr1 = 1, 2, 2, 1, 5, 9, 15, 9, 7, 7, 12;
    int[] arr2 = 1, 2, 2, 3, 4, 15, 9, 7, 12, 14;
    printIntersect(arr1, arr2);


private static void printIntersect(int[] arr1, int[] arr2) 
    Map<Integer, Integer> map = new HashMap<>();
    //put first array to map
    for (int i = 0; i < arr1.length; i++) 
        if (!map.containsKey(arr1[i])) 
            map.put(arr1[i], 1);
         else 
            map.put(arr1[i], map.get(arr1[i]) + 1);
        
    

    //check all value in array two
    for (int i = 0; i < arr2.length; i++) 
        //if exist and value>1  then decrement value
        //if value is 1 remove from map
        if (map.containsKey(arr2[i])) 
            System.out.print(arr2[i] + " ");
            if (map.get(arr2[i]) > 1) 
                map.put(arr2[i], map.get(arr2[i]) - 1);
             else 
                map.remove(arr2[i]);
            
        
    

【讨论】:

【参考方案7】:

如果数组已排序

    int a1[]=new int[] 1,2,3,5,7,8;
    int a2[]=new int [] 1,5,6,7,8,9;

     // get the length of both the array
    int n1=a1.length;
    int n2=a2.length;

 //create a new array to store the intersection
   int a3[]=new int[n1];

     //run the loop and find the intersection
    int i=0,j=0,k=0;
    while(i<n1&& j<n2) 
        if(a1[i]<a2[j]) 
         // a1 element at i are smaller than a2 element at j so increment  i
            i++;
        else if(a1[i]>a2[j]) 
         // a2 element at i are smaller than a2 element at j so increment  j

            j++;
        else 
             // intersection element store the value and increment i, j, k    to find the next element
            a3[k]=a1[i];
            i++;
            j++;
            k++;
        
    


    for(int l=0;l<a3.length;l++) 
        System.out.println(a3[l]);
    

【讨论】:

【参考方案8】:

针对仅使用一个循环的排序数组进行了优化。

    int a1[]=new int[] 1,2,3,5,7,8;
    int a2[]=new int [] 1,5,6,7,8,9;
 // sort both the array
     Arrays.sort(a1);
     Arrays.sort(a2);
     // get the length of both the array
    int n1=a1.length;
    int n2=a2.length;

 //create a new array to store the intersection
   int a3[]=new int[n1];
    
     //run the loop and find the intersection
    int i=0,j=0,k=0;
    while(i<n1&& j<n2) 
        if(a1[i]<a2[j]) 
         // a1 element at i are smaller than a2 element at j so increment  i
            i++;
        else if(a1[i]>a2[j]) 
         // a2 element at i are smaller than a2 element at j so increment  j
            
            j++;
        else 
             // intersection element store the value and increment i, j, k    to find the next element
            a3[k]=a1[i];
            i++;
            j++;
            k++;
        
    
    
    
    for(int l=0;l<a3.length;l++) 
        System.out.println(a3[l]);
    

【讨论】:

在你的答案中添加一些描述。【参考方案9】:

如何在 Java 中找到 3 个未排序数组的交集:-

我使用了核心 Java 方法,使用 for 循环和使用 Arrays.copyOf 来实现这一点。

public class Intersection 
    public void intersection3Arrays(int ar1[], int ar2[], int ar3[]) 
            Arrays. sort(ar1);
            Arrays. sort(ar2);
            Arrays. sort(ar3);

            int ar1Len = ar1.length;
            int ar2Len = ar2.length;
            int ar3Len = ar3.length;

            int larArray = ar3Len > (ar1Len > ar2Len ? ar1Len : ar2Len) ? ar3Len : ((ar1Len > ar2Len) ? ar1Len : ar2Len);
            System.out.println("The largest array is " +larArray);
            int[] inputArray1 = Arrays.copyOf(ar1, larArray);
            int[] inputArray2 = Arrays.copyOf(ar2, larArray);
            int[] inputArray3 = Arrays.copyOf(ar3, larArray);

            Integer[] inputArray11 = new Integer[inputArray1.length];
            Integer[] inputArray22 = new Integer[inputArray2.length];
            Integer[] inputArray33 = new Integer[inputArray3.length];

            for (int i = 0; i < inputArray11.length; i++) 
                if (inputArray11[i] == null)
                    inputArray1[i] = 0;
                
            
            for (int i = 0; i < inputArray22.length; i++) 
                if (inputArray22[i] == null)
                    inputArray1[i] = 0;
                
            
            for (int i = 0; i < inputArray33.length; i++) 
                if (inputArray33[i] == null)
                    inputArray1[i] = 0;
                
            

            for (int i = 0; i < inputArray11.length; i++)
                for (int j = 0; j < inputArray22.length; j++)
                    for (int k = 0; k < inputArray33.length; j++)
                    if (inputArray11[i] == inputArray22[j] && inputArray11[i] == inputArray33[k]) 
                        System.out.print(inputArray11[i]+" ");
                    
         
    public static void main(String[] args) 
        Intersection3Arrays arrays = new Intersection3Arrays();
        int ar1[] =  1, 2, 5, 10, 20, 40, 80 ;
        int ar2[] =  80, 100, 6, 2, 7, 20 ;
        int ar3[] = 3, 4, 15, 20, 30, 70, 80, 120; 
        arrays.intersection3Arrays(ar1, ar2, ar3);
    

【讨论】:

【参考方案10】:

如果您想在 python 中实现它,这是您可以找到交集的一种方法。

#find intersection
def find_intersec(list_a, list_b): 
    return set(list_a).intersection(list_b) 

#since lists are kind of like arrays in python we use two lists
list_a = [ 4, 9, 1, 17, 11, 26, 28, 10,28, 26, 66, 91] 
list_b = [9, 9, 74, 21, 45, 11, 63,10] 
print(find_intersec(list_a, list_b)) 

【讨论】:

【参考方案11】:

你可以找到两个数组的交集

T[] result = Arrays.stream(a1)
                   .filter(new HashSet<>(Arrays.asList(a2))::contains)
                   .toArray(T[]::new);

T 应该可以被引用类型替换,例如字符串、整数等

虽然上面看起来像是为每个元素创建了一个新集合,但实际上不是而是只创建一个集合实例

以上代码等价于:

List<T> list = new ArrayList<>();
HashSet<T> container = new HashSet<>(Arrays.asList(a2));
for (T s : a1)  
   if (container.contains(s)) list.add(s); 

T[] result = list.toArray(new T[0]);

【讨论】:

我同意,并且这些陈述不接受int[]作为a2 Arrays.stream(a1).filter(new HashSet&lt;&gt;(Arrays.stream(a2).boxed().collect(Collectors.toList()))::contains).toArray();【参考方案12】:

我希望这个例子是简单的一个。通过两个数组,你肯定会得到没有重复项的数组的 INTERSECTION。

private static int[] findInterserctorOfTwoArray(int[] array1, int[] array2) 
        Map<Integer,Integer> map=new HashMap<>();
        for (int element : array1) 
            for (int element2 : array2) 
                if(element==element2) 
                    map.put(element, element);
                
            
        
        int[] newArray=new int[map.size()];
        int con=0;
        for(Map.Entry<Integer, Integer> lst:map.entrySet()) 
            newArray[con]=lst.getValue();
            con++;
        
        return newArray;
    

【讨论】:

【参考方案13】:

一般测试

答案提供了几种解决方案,所以我决定找出最有效的一种。

解决方案

HashSet 基于Óscar López 基于Bilesh Ganguly Foreach 基于Ruchira Gayan Ranaweera HashMap 基于ikarayel

我们有什么

两个 String 数组包含 50% 的常见元素。 每个数组中的每个元素都是唯一的,因此没有重复项

测试代码

public static void startTest(String name, Runnable test)
    long start = System.nanoTime();
    test.run();
    long end = System.nanoTime();
    System.out.println(name + ": " + (end - start) / 1000000.  + " ms");

使用:
startTest("HashMap", () -> intersectHashMap(arr1, arr2));
startTest("HashSet", () -> intersectHashSet(arr1, arr2));
startTest("Foreach", () -> intersectForeach(arr1, arr2));
startTest("Stream ", () -> intersectStream(arr1, arr2));

解决方案代码:

哈希集
public static String[] intersectHashSet(String[] arr1, String[] arr2)
    HashSet<String> set = new HashSet<>(Arrays.asList(arr1));
    set.retainAll(Arrays.asList(arr2));
    return set.toArray(new String[0]);

溪流
public static String[] intersectStream(String[] arr1, String[] arr2)
    return Arrays.stream(arr1)
            .distinct()
            .filter(x -> Arrays.asList(arr2).contains(x))
            .toArray(String[]::new);

前锋
public static String[] intersectForeach(String[] arr1, String[] arr2)
    ArrayList<String> result = new ArrayList<>();
    for(int i = 0; i < arr1.length; i++)
        for(int r = 0; r < arr2.length; r++)
            if(arr1[i].equals(arr2[r]))
                result.add(arr1[i]);
        
    
    return result.toArray(new String[0]);

哈希映射
public static String[] intersectHashMap(String[] arr1, String[] arr2)
    HashMap<String, Integer> map = new HashMap<>();
    for (int i = 0; i < arr1.length; i++)
        map.put(arr1[i], 1);

    ArrayList<String> result = new ArrayList<>();
    for(int i = 0; i < arr2.length; i++)
        if(map.containsKey(arr2[i]))
            result.add(arr2[i]);
    return result.toArray(new String[0]);

测试过程


让我们看看如果我们给方法一个 20 元素的数组会发生什么:

HashMap: 0.105 ms
HashSet: 0.2185 ms
Foreach: 0.041 ms
Stream : 7.3629 ms

正如我们所见,Foreach 方法做得最好。但是 Stream 方法几乎慢了 180 倍。


让我们用500 元素继续测试:

HashMap: 0.7147 ms
HashSet: 4.882 ms
Foreach: 7.8314 ms
Stream : 10.6681 ms

在这种情况下,结果发生了巨大变化。现在最高效的是 HashMap 方法。


使用10 000 元素进行下一次测试:

HashMap: 4.875 ms
HashSet: 316.2864 ms
Foreach: 505.6547 ms
Stream : 292.6572 ms

最快的还是HashMap方法。 Foreach 方法变得相当缓慢。


结果

如果有 Foreach 方法。他在这一类别中的速度非常出色。

在这种情况下,最好的顶部将如下所示:

    Foreach HashMap HashSet Stream - 在这种情况下最好不要使用

但如果您需要处理大数据,那么最好的选择是使用基于HashMap 的方法。

所以最好的顶部是这样的:

    HashMap HashSet Stream Foreach

【讨论】:

为什么不使用 IntStream?【参考方案14】:

原始迭代器:比 HashSet 快 6 倍

在 10,000,000 个随机元素(值介于 0 到 200,000,000 之间)的 排序 数组上进行测试。在具有 4GB 堆空间的 10 处理器 i9 上进行了测试。两个数组的排序时间为 1.9 秒。

结果:

primitive() - 1.1 秒

public static int[] primitive(int[] a1, int[] a2) 
    List<Integer> list = new LinkedList<>();
    OfInt it1 = Arrays.stream(a1).iterator();
    OfInt it2 = Arrays.stream(a2).iterator();
    int i1 = it1.next();
    int i2 = it2.next();
    do 
      if (i1==i2) 
        list.add(i1);
         i1 = it1.next();
      
      if (i1 < i2) i1 = it1.next();
      if (i2 < i1) i2 = it2.next();
     while(it1.hasNext() && it2.hasNext());
    if (i1==i2) list.add(i1);
    return list.stream().mapToInt(Integer::intValue).toArray();
  

boxed() - 6.8 秒

  public static int[] boxed(int[] a1, int[] a2) 
    return Arrays.stream(a1)
                   .filter(new HashSet<>(Arrays.stream(a2).boxed()
                         .collect(Collectors.toList()))::contains)
                   .toArray();
  

【讨论】:

以上是关于Java,找到两个数组的交集的主要内容,如果未能解决你的问题,请参考以下文章

在Python / Numpy / Scipy中找到两个数组之间的插值交集

如何求两个数组的交集??

350. 两个数组的交集 II (Java)

LeetCode Java刷题笔记—349. 两个数组的交集

LeetCode Java刷题笔记—349. 两个数组的交集

如何使用java获取两个数组之间的交集? [关闭]