两个数组的交集与重复

时间:2012-11-30 09:04:33

标签: java algorithm

我正在尝试创建一个方法,使两个数组交叉重复。

示例:{1,2,5,4,1,3} and {1,2,1} -> {1,1,2}.

我有一个交叉但没有重复的方法。

  public int[] findSameElements(int[] p1, int[] p2) {
    int count = 0;
    for (int i = 0; i < p1.length; i++) {
      for (int j = 0; j < p2.length; j++) {
        if (p1[i] == p2[j]) {
          count++;
          break;
        }
      }
    }

    int[] result = new int[count];
    count = 0;
    for (int i = 0; i < p1.length; i++) {
      for (int j = 0; j < p2.length; j++) {
        if (p1[i] == p2[j]) {
          result[count++] = p1[i];
          break;
        }
      }
    }

    return result;
  }

如何在不使用Arrays.*List.*的情况下添加重复内容?

5 个答案:

答案 0 :(得分:5)

请尝试以下功能:

public int[] findSameElements(int[] p1, int[] p2)
{
    int count = 0;
    bool[] choosen = new bool[p2.length];

    for (int i = 0; i < p1.length; i++)
    {
        for (int j = 0; j < p2.length; j++)
        {
            if (!choosen[j] && p1[i] == p2[j])
            {
                choosen[j] = true;
                count++;
                break;
            }
        }
    }

    int[] result = new int[count];
    count = 0;
    for (int i = 0; i < p2.length; i++)
    {
        if (choosen[i])
        {
            result[count] = p2[i];
            count++;
        }
    }

    return result;
}

如果有必要,您还应该应用排序,此解决方案具有O(N ^ 2)复杂度。 也可能使O(NLogN)复杂化。

答案 1 :(得分:2)

您可以构建histogram(将表示为Map<Integer,Integer>)并且:

  1. 将list1中的所有元素(及其重复次数)插入直方图
  2. 为每个元素e迭代list2:
    - 如果直方图包含元素e(具有正值):打印(或附加到新列表)e,并减小直方图中e的值
  3. 请注意,此解决方案为O(n+m)时间(平均大小写)和O(min{n,m})空间。


    代码示例(使用List<T>代替数组 - 但当然可以轻松修改):

    private static <T> Map<T,Integer>  populateHistogram(List<T> list) {
        Map<T,Integer> histogram = new HashMap<T, Integer>();
        for (T e : list) {
            Integer val = histogram.get(e);
            histogram.put(e, val == null ? 1 : val+1);
        }
        return histogram;
    }
    public static <T> List<T> generateInterectionList(List<T> list,Map<T,Integer> histogram ) {
        List<T> res = new ArrayList<T>();
        for (T e : list) { 
            Integer val = histogram.get(e);
            if (val != null && val > 0) { 
                res.add(e);
                histogram.put(e,val - 1);
            }
        }
        return res;
    }
    public static <T> List<T> getIntersection(List<T> list1, List<T> list2) {
        Map<T,Integer> histogram = populateHistogram(list1.size() > list2.size() ? list2 : list1);
        return generateInterectionList(list1.size() > list2.size() ? list2 : list1,histogram);
    }
    public static void main(String[]args){
        List<Integer> list1 = Arrays.asList(new Integer[]{1,2,5,4,1,3}); 
        List<Integer> list2 = Arrays.asList(new Integer[]{1,2,1}); 
        System.out.println(getIntersection(list1, list2));
    }
    

    注意它也可以在O(nlogn)时间和O(logn)空间(对于排序算法的堆栈跟踪)中进行排序,然后与每个列表的一个指针并行迭代

    伪代码:

    重复i1&lt; list1.length和i2&lt; list2.length:

    1. 如果list1 [i1] == list2 [i2]:
      - 打印清单1 [i1]
      - 增加i1,i2
    2. 如果list1 [i1]&gt; list2中[12]:
      - 增加i2
    3. 否则:
      - 增加i1

答案 2 :(得分:0)

有没有理由不使用收藏品? retainAll(...)方法可以满足您的需求:

List<Integer> list1 = ...
List<Integer> list2 = ...
List<Integer> intersection = list1.retainAll( list2 );

答案 3 :(得分:0)

一种方法是使用哈希表。从两个数组中创建两个单独的哈希表。键值对是(element,count)。现在浏览较小的哈希表并打印出count_min = min的每个元素count_min次数(表a中元素的计数,表b中元素的计数)。这是一种具有额外空间复杂度的线性算法。

空间复杂度= O(n + m)其中n和m是两个数组的大小。 时间复杂O(n)其中n> m。

答案 4 :(得分:0)

如果您对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();
}