在接受采访时我被问到以下问题:
在它们的排序内容上组合两个迭代器,使得 结果迭代器应该迭代这些2的组合 O(1)时间内按顺序排列的迭代器(这些迭代器遍历a 字符串)。
我写了下面的代码,但我确信它在O(1)时间内没有执行。您对匹配面试问题设置的约束有什么建议?
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class iteratorCombine {
// assumption1: elements are hardcoded
// assumption2: both iterators have equal number of elements
public static void main(String[] args) {
iteratorCombine testObj = new iteratorCombine();
Set<String> firstSet = new TreeSet<String>();
Set<String> secondSet = new TreeSet<String>();
Set<String> combinedSet;
firstSet = testObj.storeElements1(firstSet);
secondSet = testObj.storeElements2(secondSet);
Iterator<String> it1 = firstSet.iterator();
Iterator<String> it2 = secondSet.iterator();
combinedSet = testObj.combine(it1, it2);
// output
Iterator<String> itComb = combinedSet.iterator();
while(itComb.hasNext()){
System.out.println(itComb.next());
}
}
public Set<String> storeElements1(Set<String> firstSet){
firstSet.add("first3");
firstSet.add("first1");
firstSet.add("first2");
return firstSet;
}
public Set<String> storeElements2(Set<String> secondSet){
secondSet.add("second3");
secondSet.add("second1");
secondSet.add("second2");
return secondSet;
}
public Set<String> combine(Iterator<String> it1, Iterator<String>it2){
String firstEle, secondEle;
Set<String> combinedSet = new TreeSet<String>();
while (it1.hasNext() && it2.hasNext()) {
firstEle = it1.next();
secondEle = it2.next();
combinedSet.add(firstEle+secondEle);
}
return combinedSet;
}
}
答案 0 :(得分:5)
如果您不延长iterator
并支持peek
功能,我相信您无法做到这一点。这样的迭代器并不那么难。这是一种方法。
static class PeekingIterator<T> implements Iterator<T> {
private final Iterator<T> iterator;
private T temp;
public PeekingIterator(Iterator<T> iterator) {
this.iterator = iterator;
}
public T peek() {
//if there is no peek, advance the iterator and store its value, return the peek otherwise
if(temp==null){
temp = this.iterator.next();
}
return temp;
}
@Override
public T next() {
//if we already have a peek,return it and nullify it, otherwise do normal next()
if(temp!=null){
T t = temp;
temp = null;
return t;
}else{
return this.iterator.next();
}
}
@Override
public boolean hasNext() {
return this.iterator.hasNext() || temp!=null;
}
}
一旦你可以窥视,其余的很容易,你可以使用两个偷看迭代器构建SortedIterator
,查看两个迭代器并推进具有较小元素的迭代器。
static class SortedIterator<T extends Comparable<T>> implements Iterator<T>{
private final PeekingIterator<T> peekingIterator1;
private final PeekingIterator<T> peekingIterator2;
SortedIterator(Iterator<T> source1, Iterator<T> source2){
peekingIterator1 = new PeekingIterator<>(source1);
peekingIterator2 = new PeekingIterator<>(source2);
}
@Override
public boolean hasNext() {
return peekingIterator1.hasNext() || peekingIterator2.hasNext();
}
@Override
public T next() {
if(!peekingIterator1.hasNext()){
return peekingIterator2.next();
}
if(!peekingIterator2.hasNext()){
return peekingIterator1.next();
}
T peek1 = peekingIterator1.peek();
T peek2 = peekingIterator2.peek();
if(peek1.compareTo(peek2)<0){
return peekingIterator1.next();
}
return peekingIterator2.next();
}
}
分析显而易见,SortedIterator.next
和SortedIterator.hasNext
在恒定时间内运行。
答案 1 :(得分:0)
我有一个类似的用例,但不是只有 2 个迭代器,我必须合并动态数量的迭代器。迭代器的数量可以超过2个。例如3个迭代器、4个迭代器或更多。
我使用了与 Sleiman Jneidi 建议的相同的解决方案。我修改了 SortedIterator 以支持多个迭代器,还支持根据需要按升序或降序排序。
对于 PeekingIterator
,我使用了 Apache 公共集合的 Peeking 迭代器。
这是我的排序迭代器,如果有人可能需要合并多个排序迭代器,他们可以参考这个:
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections4.iterators.PeekingIterator;
/**
* This class is special implementation of Iterator.
* It lets multiple sorted iterators to be merged to a single sorted iterator.
* It will use given comparator to compare values from multiple iterators.
*
*/
public class SortedMergedIterator<T> implements Iterator<T> {
/**
* Comparator that will be used to compare values from across the iterators.
*/
private final Comparator<? super T> comparator;
/**
* List of sorted iterators which are required to be merged to a single sorted iterator.
*/
private final List<PeekingIterator<T>> peekingIterators;
/**
* By default the sort order will be considered as ascending order.
*
* It this flag is set to true, the elements will be sorted in descending order.
* In this case, it is pre-requisite that all the iterators being passed should be sorted in ascending order.
*/
private final boolean sortOrderDescending;
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators) {
this(comparator, iterators, false);
}
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators, final boolean sortOrderDescending) {
this.comparator = comparator;
this.peekingIterators = iterators.stream().map(iterator -> new PeekingIterator<>(iterator)).collect(Collectors.toList());
this.sortOrderDescending = sortOrderDescending;
}
@Override
public boolean hasNext() {
// If at least one of the child iterator has next element.
return this.peekingIterators.stream().anyMatch(Iterator::hasNext);
}
@Override
public T next() {
// Peek next value from all the iterators.
final List<T> peekedValues = this.peekingIterators.stream().map(PeekingIterator::peek).collect(Collectors.toList());
// Find the minimum value from all the peeked values.
final T minElement = peekedValues
.stream()
.filter(Objects::nonNull)
.min(this.sortOrderDescending ? this.comparator.reversed() : this.comparator)
.orElse(null);
// Return the next element from an iterator for which minimum value is found.
return this.peekingIterators.get(peekedValues.indexOf(minElement)).next();
}
}
使用这个迭代器的例子:
public static void main(String[] args) {
// Example of ascending order sorted iterators.
final List<Integer> list1 = Lists.newArrayList(4,7,11,12,16);
final List<Integer> list2 = Lists.newArrayList(1,3,5,10,15);
final List<Integer> list3 = Lists.newArrayList(6,8,13,18,20);
final List<Integer> list4 = Lists.newArrayList(2,9,14,17,19);
final SortedMergedIterator<Integer> sortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list1.iterator(), list2.iterator(), list3.iterator(), list4.iterator()));
while (sortedIterator.hasNext()) {
System.out.println(sortedIterator.next());
}
System.out.println();
// Example of descending order sorted iterators.
final List<Integer> list5 = Lists.newArrayList(16,12,11,7,4);
final List<Integer> list6 = Lists.newArrayList(15,10,5,3,1);
final List<Integer> list7 = Lists.newArrayList(20,18,13,8,6);
final List<Integer> list8 = Lists.newArrayList(19,17,14,9,2);
final SortedMergedIterator<Integer> descSortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list5.iterator(), list6.iterator(), list7.iterator(), list8.iterator()), true);
while (descSortedIterator.hasNext()) {
System.out.println(descSortedIterator.next());
}
}