k个没有重复项的排序数组的迭代器实现-面试问题

时间:2018-12-09 19:39:30

标签: java arrays performance iterator priority-queue

问题的第一部分是:
给定k排序后的数组,请实现一个迭代器,用于以升序对数组的元素进行迭代。例如:

如果我们有:a1 = {1,3,5}, a2 = {2,4,4,5},则调用实现了7次的迭代器的next()方法将返回:1,2,3,4,4,5,5

我成功实现了这一部分,并在下面编写了代码。

第二部分是当next()方法不返回重复项时实现此迭代器类。对于上面示例中的数组,如果我们调用next()方法 5 次,我们将得到:1,2,3,4,5(如果我们调用6次,则需要获取一个异常)。

我认为这并不难-只需使用HashSet字段,在将它们输入到堆中时将项目添加到此集合中,然后将其实现为一个循环,当您获得唯一的项目时终止。
这种方法的问题在于方法hasNext()效率不高:您将不得不在以后的调用中迭代将插入到堆中的元素,以了解在将来的{调用中您实际上将具有唯一元素{1}}。

您是否知道如何以有效的方式实现不带重复项的迭代器?

next()

2 个答案:

答案 0 :(得分:2)

我认为,对您的原始代码进行少量修改将消除重复项:

  1. 创建迭代器时,存储所有数组的max元素(您必须检查每个k数组的最后一个元素以找到最大值)。

  2. 还存储上一次对next()的调用返回的元素。可以将其初始化为Integer.MIN_VALUE,并在每次调用next()时进行修改。

  3. hasNext()仅检查最后一个元素是否返回

  4. 新的next()重复调用原始的next(),直到找到比先前返回的元素大的元素为止。

这是修改您的代码的实现(可能需要进行一些小的修改以支持诸如空输入之类的极端情况):

...
private int max; // the maximum element
private int last = Integer.MIN_VALUE; // the last element returned by next()

public ComplexIterator(int[][] lists) {
    minHeap = new PriorityQueue<IndexedArrayValue>();
    int numOfLists = lists.length;

    this.lists = lists;
    max = lists[0][lists[0].length-1];
    for (int i = 0; i < numOfLists; i++) {
        minHeap.add(new IndexedArrayValue(i, 0, lists[i][0]));
        if (lists[i][lists[i].length-1] > max) {
            max = lists[i][lists[i].length-1];
        }
    }
}

@Override
public boolean hasNext() {
    return last < max;
}

@Override
public Integer next() {
    if (!hasNext())
        throw new NoSuchElementException();

    int value;
    do {
        IndexedArrayValue indArrVal = minHeap.poll();
        int arrayId = indArrVal.arrayId;
        int index = indArrVal.index;
        value = indArrVal.value;
        int nextIndex = index + 1;

        if (nextIndex < lists[arrayId].length) {
            minHeap.add(new IndexedArrayValue(arrayId, nextIndex, lists[arrayId][nextIndex]));
        }
    }
    while (value <= last);
    last = value;

    return value;
}

答案 1 :(得分:0)

您可以使用TreeSet使其更简单:

public final class UniqueSortedIterator implements 
    Iterator<Integer> {

    private final Iterator<Integer> base;

    public UniqueSortedIterator(int[][] arrays) {
        Set<Integer> set = new TreeSet<>();
        for (int[] array : arrays) {
            for (int item : array) {
                set.add(item);
            }
        }
        this.base = set.iterator();
    }

    @Override
    public boolean hasNext() {
        return this.base.hasNext();
    }

    @Override
    public Integer next() {
        return this.base.next();
    }
}

树集既具有独特元素,又保持自然秩序。简单测试:

int[] first = { 1, 3, 5 };
int[] second = { 2, 4, 4, 5 };
Iterator<Integer> usi = new UniqueSortedIterator(new int[][] { first, second });
while (usi.hasNext()) {
    System.out.println(usi.next());
}