在Java中查找一个int子集的补充

时间:2012-11-02 10:58:06

标签: java arrays algorithm sorting set

我们让int[] A = new int[1000]int[] subA = new int [300] subA \in AsubAA的子集)。如何在Java中以最快的方式查找数组A \ subA?给定的数组AsubA都已排序。

编辑:抱歉,忘记提到数组包含不同的元素,只是它们包含其他结构的矩形,如矩阵行。

我正在考虑这个解决方案:

// supp is short for supplement
int[] supp = new int[A.length - subA.length];
int j = A[0], c = 0;
for (int i = 0; i < subA.lengh; i++) {
    // elegantly can be: while (j < subA[i]) supp[c++] = j++;
    while (j < subA[i]) {
        supp[c] = j;
        c++; j++;
    }
    j = subA[i] + 1;
}

目前正在测试这种方法。答案准备好后我会回来的。

4 个答案:

答案 0 :(得分:4)

尝试这样的事情:

// A index
int ai = 0;
// subA index
int sai = 0;
// result array
int[] result = new int[A.length - subA.length];
// index in result array
int resi = 0;

while ai < A.length && sai < subA.length;
    // same elements - ignore
    if (A[ai] == subA[sai]) {
        ai++;
        sai++;
    // found an element in A that does not exist in subA
    } else {
        // Store element
        result[resi] = A[ai];
        resi++;
        ai++;
    }
}

// Store elements that are left in A
for (;ai < A.length; ai++, resi++) {
    result[resi] = A[ai];
}

答案 1 :(得分:1)

如果您说元素已排序且各不相同,那么您只需在A中找到subA的第一个元素的索引,然后使用System.arrayCopy()以最有效的方式复制数据:

    int index = Arrays.binarySearch(A, subA[0]);

    int[] diff = new int[A.length - subA.length];

    System.arraycopy(A, 0, diff, 0, index);
    System.arraycopy(A, index+subA.length, diff, index, A.length-index-subA.length);

PS。我没有检查所有的索引位置和计算,但是你明白了。

答案 2 :(得分:0)

既然你说两个数组都是排序的,这听起来像是“我希望你遍历两个数组并从sub中删除A部分之间的部分”对我来说有点做作业。

所以让我们尝试起草

  • 数组A按1000个成员排序
  • subA按300名成员排序
  • arrayA具有所有subA的元素

意味着我们可以做类似的事情......

public ArrayList findDifferences(int[] arrayA, int[] subA)
{
    ArrayList retVal = new ArrayList();
    for(int i = 0; i < arrayA.size; i++)
    {  
        if(arrayA[i] < subA[index]
            retVal.add(arrayA[i]);
        else if(arrayA[i] == subA[index])
            index++;
    }
    return retVal;
}

我会说不知何故你可以计算要复制的范围,但我猜它最终会像这样。

然后就是这个

 List a = new List();
 a.addAll(arrayA);
 List b = new List();
 b.addAll(subA);
 a.removeAll(b);
 return a;

答案 3 :(得分:0)

最快最有效的方法是使A \ SubA成为A上的视图,即不保留对元素的自己引用,但由A和SubA支持。这类似于difference from Guava Sets

当然,必须考虑在创建该视图后对A和SubA的更改,这可能是优势或劣势,具体取决于您的情况。

任意列表的示例性实现(即在您的情况下,使用new ImmutableSubarrayList<E>(Arrays.asList(A),Arrays.asList(SubA))

import java.util.AbstractSequentialList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;


public class ImmutableSubarrayList<E extends Comparable<E>> extends AbstractSequentialList<E>{

    final List<E> a, subA;
    final int size;

    public ImmutableSubarrayList(List<E> aParam, List<E> subAParam){
        super();
        a = aParam;
        subA = subAParam;
        assert a.containsAll(subA) : "second list may only contain elements from first list";

        // Iterate over a, because a.size()-subA.size() may not be correct if a contains equal elements. 
        int sizeTemp = 0;
        for (E element : a){    
            if (!subA.contains(element)){
                sizeTemp++;
            }
        }
        size = sizeTemp;
    }

    public int size() {
        return size;
    }

    public ListIterator<E> listIterator(final int firstIndex) {
        //create a ListIterator that parallely 
        // iterates over a and subA, only returning the elements in a that are not in subA
        assert (firstIndex >=0 && firstIndex <= ImmutableSubarrayList.this.size()) : "parameter was "
                           +firstIndex+" but should be betwen 0 and "+ImmutableSubarrayList.this.size();
        return new ListIterator<E>() {

            private final ListIterator<E> aIter = a.listIterator();
            private final ListIterator<E> subAIter = subA.listIterator();
            private int nextIndex = 0;

            {
                for (int lv = 0; lv < firstIndex; lv++ ){
                    next();
                }
            }

            @Override
            public boolean hasNext() {
                return nextIndex < size;
            }

            @Override
            public void add(E arg0) {
                throw new UnsupportedOperationException("The list being iteratred over is immutable");
            }

            @Override
            public boolean hasPrevious() {
                return nextIndex > 0;
            }

            @Override
            public int nextIndex() {
                return nextIndex;
            }

            @Override
            public E next() {
                if (!hasNext()){
                    throw new NoSuchElementException();
                }
                nextIndex++;
                return findNextElement();
            }

            @Override
            public E previous() {
                if (!hasPrevious()){
                    throw new NoSuchElementException();
                }
                nextIndex--;
                return findPreviousElement();
            }

            @Override
            public int previousIndex() {
                return nextIndex-1;
            }

            @Override
            public void set(E arg0) {
                throw new UnsupportedOperationException("The list being iteratred over is immutable");
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("The list being iteratred over is immutable");          
            }

            private E findNextElement() {
                E potentialNextElement = aIter.next();
                while (subAIter.hasNext()){
                    E nextElementToBeAvoided = subAIter.next();
                    subAIter.previous();
                    assert (potentialNextElement.compareTo(nextElementToBeAvoided) > 0) : 
                        "nextElementToBeAvoided should not be smaller than potentialNextElement";
                    while (potentialNextElement.compareTo(nextElementToBeAvoided) == 0){
                        potentialNextElement = aIter.next();
                    }
                    subAIter.next();
                }
                return potentialNextElement;
            }

            //in lack of lambdas: clone of findNextElement()
            private E findPreviousElement() {
                E potentialPreviousElement = aIter.previous();
                while (subAIter.hasPrevious()){
                    E previousElementToBeAvoided = subAIter.previous();
                    subAIter.previous();
                    assert (potentialPreviousElement.compareTo(previousElementToBeAvoided) < 0) : 
                        "previousElementToBeAvoided should not be greater than potentialPreviousElement";
                    while (potentialPreviousElement.compareTo(previousElementToBeAvoided) == 0){
                        potentialPreviousElement = aIter.previous();
                    }
                    subAIter.previous();
                }
                return potentialPreviousElement;
            }
        };
    }
}