结合2个数组的唯一整数的最快方法

时间:2012-02-26 22:02:50

标签: java performance

如果我有2个阵列:

arr1 = {9,8}
arr2 = {13,12,10,9,8}

我想得到:

{13,12,10}

给出阵列:

arr1 = {23,22,21,20,19,18,17,16}
arr2 = {21,17}

结果将是:

{23,22,20,19,18,16}

所以基本上我得到了arr1或arr2中的数字,但不是两者都有。

  • 2个阵列的长度可能不同。
  • 2个数组按降序排序,最终数组也必须具有此属性。
  • 这已经完成了数百万次,所以我尽量减少/阻止对象分配。这就是为什么我没有使用套装来完成这项工作。

4 个答案:

答案 0 :(得分:4)

由于您按排序顺序排列数组,因此它们之间的重叠非常重要 - 您可以从单个数组中非常快速地处理非重叠部分,而无需检查另一个数组。

9 8 7 5
     6 4 3 2

E.g。 9,8,7可以直接从数组1中获取,然后中间部分需要更加小心,然后你可以直接从数组2中获取4,3,2。这将有助于知道输入的非重叠部分是否是可能意义重大。

对于中间部分,您只需要重复从每个数组中取出下一个未处理元素的最大值(并删除重复项)。

你需要一个数组来获得结果 - 一种方法是分配一个足够大的数组来容纳两个输入数组,最坏的情况是,然后将System.arrayCopy()转换成右边的新数组大小,或只是保持实际元素数量的计数。另一种方法是使用ArrayList,然后根据需要执行toarray

答案 1 :(得分:2)

你正在寻找两套的EXOR。由于阵列是预先排序的,我认为这比它看起来更简单。伪代码

  
      
  1. 比较每个数组的第一个元素
  2.   
  3. 如果不相等,请将较大的一个添加到唯一集合
  4.   
  5. else删除两个元素
  6.   
  7. 如果您已到达一个数组的末尾,请将另一个数组中剩余的所有元素添加到唯一集合
  8.   

这是greedy O(n)解决方案。这是一个实施,经过轻微测试:D

/**
 * Returns the sorted EXOR of two sorted int arrays (descending). Uses
 * arrays, index management, and System.arraycopy.
 * @author paislee
 */
int[] arrExor(int[] a1, int[] a2) {

    // eventual result, intermediate (oversized) result
    int[] exor, exor_builder = new int[a1.length + a2.length];
    int exor_i = 0; // the growing size of exor set

    int a1_i = 0, a2_i = 0; // input indices
    int a1_curr, a2_curr; // elements we're comparing

    // chew both input arrays, greedily populating exor_builder
    while (a1_i < a1.length && a2_i < a2.length) {

        a1_curr = a1[a1_i];
        a2_curr = a2[a2_i];

        if (a1_curr != a2_curr) {
            if (a1_curr > a2_curr)
                exor_builder[exor_i++] = a1[a1_i++];
            else
                exor_builder[exor_i++] = a2[a2_i++];
        } else {
            a1_i++;
            a2_i++;
        }        
    }

    // copy remainder into exor_builder
    int[] left = null; // alias for the unfinished input
    int left_i = 0, left_sz = 0; // index alias, # elements left

    if (a1_i < a1.length) {
        left = a1;
        left_i = a1_i;
    } else {
        left = a2;
        left_i = a2_i;
    }

    left_sz = left.length - left_i;
    System.arraycopy(left, left_i, exor_builder, exor_i, left_sz);
    exor_i += left_sz;

    // shrinkwrap and deliver
    exor = new int[exor_i];
    System.arraycopy(exor_builder, 0, exor, 0, exor_i);
    return exor;
}

答案 2 :(得分:1)

基本上你想使用合并排序。通常它用于合并升序列表,但也可以降序。

http://en.wikipedia.org/wiki/Merge_sort

由于您有两个已排序的集合,因此合并为O(n)

答案 3 :(得分:0)

使用集合,但重复使用它们并在每次迭代开始时清空它们。或者,由于保证数组被排序,您可以使用与合并相当的东西。 (维护两个数组的索引。在每个步骤中,如果2个索引指向相同的元素,则将索引移过这些元素,并且不向输出添加任何内容。否则,将更大的元素添加到输出中,并且只推进该指数。)