我发现了以下面试问题here.
SortedIterator-由列表列表组成,列表中的int值已排序 每个列表。调用next()时必须提供下一个排序后的值。
必须实现方法 *构造函数 * 下一个() * hasNext()
[[1、4、5、8、9],[3、4、4、6],[0、2、8]]
next()-> 0,1,2,3,4,4,4 ...
我用Java编写了一个快速实现:
package com.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class SortedIterator implements Iterator<Integer> {
private final List<Integer> mFlattenedList;
private final Iterator<Integer> mIntegerIterator;
SortedIterator(final List<List<Integer>> lists) {
mFlattenedList = flattenLists(lists);
mIntegerIterator = mFlattenedList.iterator();
}
private List<Integer> flattenLists(final List<List<Integer>> lists) {
final List<Integer> result = new ArrayList<>();
for (List<Integer> list : lists) {
for (int value : list) {
result.add(value);
}
}
Collections.sort(result);
return result;
}
@Override
public boolean hasNext() {
return mIntegerIterator.hasNext();
}
@Override
public Integer next() {
return mIntegerIterator.next();
}
}
时间:用O(K * N)展平输入列表+ O(N * K)遍历展平列表= O(N * K)
空格:O(N * K)用于存储扁平化列表。
N-列表数。
K-每个列表中的元素数。
但是链接中的answer说:
有一个使用优先级的时间复杂度为O(logN)的解决方案 队列。也许一个面试官期望这样的事情,我不 知道。
O (log N)
怎么可能?如果使用了优先级队列,则每次调用hasNext()
时,都需要检查队列是否为空(O(1)
)。然后我们调用next()
,根据table从队列(O(log (N*K)
)中提取min元素(对于任何实现)。由于我们需要调用next()
N * K次,因此我们需要O(N * K * log (N*K)
遍历所有元素。
答案 0 :(得分:2)
解决方案的O(logN)复杂度是每个元素的复杂度,而不是迭代所有值的复杂度。
解决方案如下:
首先定义一个名为ListValue
的新类,该类存储值以及它来自的列表的索引。这些应该与使用值的其他ListValue
对象相当。
构造函数:初始化一个名为PriorityQueue<ListValue>
的{{1}}并将N个列表中的每一个的第一个元素放入pq
中。
next():弹出pq
前面的ListValue
。其中的值是要返回的值,但首先,将下一个元素从该pq
的列表移至ListValue
中。复杂度为O(log N),因为我们删除了一个元素并向最多包含N个元素的pq
添加了一个元素。
请注意,该解决方案不会一次将所有N * K个值都保留在优先级队列中,而是仅从N个列表中的每个中保留一个“ next”值。因此,优先级队列始终(最多)具有N个元素,因此其操作全部为O(log N)。
要了解为什么这样做,请回想每个列表都已排序,因此最小未使用值必须出现在某个列表的“前部”(不包括已经消耗的值)。然后,请注意,优先级队列恰好包含每个列表的“前”元素-当我们从与删除元素相同的列表中向pq
添加元素时,我们强制在next()
中发生。因此,pq
始终会包含最小的未使用值(直到所有值都用尽)。