多个列表中的常见元素

时间:2015-09-15 22:57:15

标签: java arrays sorting search collections

我需要在多个预先排序的列表中找到所有公共元素(如果所有列表中都存在重复项,它们必须列出多次)。列表的数量将由用户确定。我正在尝试找到一种具有O(n)效率的算法。

我一直在玩下面的代码,但是如果我还不知道有多少列表,我就无法弄清楚如何使这个工作:

Integer[] a = {2, 2, 4, 6, 7, 11};
Integer[] b = {2, 2, 3, 5, 7, 14}
int i = 0;
int j = 0;
while(i < a.length && j < b.length) {
   if(a[i] == b[j]) {
      System.out.print(a[i] + " ");
      i++;
      j++;
   } else if(a[i] > b[j]) {
        j++;
   } else {
        i++;
   }
}

期望的输出:2 2 7

2 个答案:

答案 0 :(得分:0)

我认为这有效,但我只是在几个案例中进行了检查。

public static void main(String[] args) {
    int[][] arrays = {{1, 1, 2, 2, 2, 3, 7, 7, 10, 10, 10}, 
                      {1, 1, 1, 2, 2, 3, 3, 7, 7, 7, 10}, 
                      {1, 1, 2, 2, 3, 7, 7, 10}};
    int n = arrays.length;
    int[] indices = new int[n];
    while (checkBounds(arrays, indices)) {
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < n; i++)
            max = Math.max(max, arrays[i][indices[i]]);
        boolean allEqualMax = true;
        for (int i = 0; i < n; i++) {
            if (arrays[i][indices[i]] < max) {
                indices[i]++;
                allEqualMax = false;
            }
        }
        if (allEqualMax) {
            System.out.print(max + " ");
            for (int i = 0; i < n; i++)
                indices[i]++;
        }
    }
}

private static boolean checkBounds(int[][] arrays, int[] indices) {
    for (int i = 0, n = arrays.length; i < n; i++)
        if (indices[i] >= arrays[i].length)
            return false;
    return true;
}

答案 1 :(得分:0)

以下内容适用于List而非数组,因为处理动态数量的列表稍微复杂一些,但它支持所有ListCollection和{{1类型。

适用于任何类型的Iterable值列表,例如ComparableIntegerLongDoubleString,...

可以根据需要修改代码以处理DateInteger[]或任何其他数字基元类型,但您必须克隆每种数组类型的代码。

未进行验证。列表必须预先排序,不允许空值。

int[]

测试

@SafeVarargs
@SuppressWarnings("unchecked")
private static <E extends Comparable<E>> List<E> getCommonValues(Iterable<? extends E> ... lists) {
    // For each list: Get iterator and first value
    Iterator<? extends E>[] iter  = new Iterator[lists.length];
    E[] value = (E[])new Comparable[lists.length];
    for (int i = 0; i < lists.length; i++) {
        iter[i] = lists[i].iterator();
        value[i] = (iter[i].hasNext() ? iter[i].next() : null);
    }

    List<E> commonValues = new ArrayList<>();
    while (true) {

        // Find value count, lowest value, and count of lowest value
        int valueCount = 0, lowestCount = 0;
        E lowestValue = null;
        for (int i = 0; i < lists.length; i++)
            if (value[i] != null) {
                valueCount++;
                int cmp = (lowestValue == null ? -1 : value[i].compareTo(lowestValue));
                if (cmp < 0) {
                    lowestCount = 1;
                    lowestValue = value[i];
                } else if (cmp == 0) {
                    lowestCount++;
                }
            }

        // Exit loop if no more values
        if (valueCount == 0)
            break;

        // Save common value if all values were lowest value
        if (lowestCount == lists.length)
            commonValues.add(lowestValue);

        // For each list: Get next value if value was lowest value
        for (int i = 0; i < lists.length; i++)
            if (value[i] != null && value[i].compareTo(lowestValue) == 0)
                value[i] = (iter[i].hasNext() ? iter[i].next() : null);
    }

    return commonValues;
}

输出

List<Integer> common = getCommonValues(Arrays.asList(2, 2, 4, 6, 7, 11),
                                       Arrays.asList(2, 2, 3, 5, 7, 14),
                                       Arrays.asList(2, 2, 2, 3, 3, 4, 5, 6, 7, 11, 14));
System.out.println(common);