我今天接受了采访,他们给了我:
列表A有:
f
google
gfk
fat
...
列表B有:
hgt
google
koko
fat
ffta
...
他们让我将这两个列表合并到一个已排序的列表C中。
我说的是:
我将List B添加到List A,然后我从List A创建了一个Set,然后从Set创建一个List。面试官告诉我这些名单很大,这种方法对表现不利,他说这将是一个nlog(n)。
对这个问题有什么更好的解决方法?
答案 0 :(得分:5)
那么你的方法需要额外的O(3N)空间(连接的List,Set和结果列表),这是它的主要低效率。
我会使用您选择的任何排序算法对ListA和ListB进行排序(QuickSort就地需要O(1)空间;我相信Java的默认排序策略是MergeSort,它通常需要O(N)额外空间),然后使用类似MergeSort的算法检查ListA的“当前”索引到ListB的当前索引,插入应该首先进入ListC的元素,并递增该列表的“当前”索引计数。仍然是NlogN,但你避免了从收集到收集的多轮转换;此策略仅使用O(N)额外空间(对于ListC;如果MergeSort源列表,您将需要N / 2空间)。
IMO算法的下限是做面试官想要的 O (NlogN)。虽然最佳解决方案在该增长模型中具有更少的额外空间并且更有效,但您无法在少于NlogN时间内对两个未排序的字符串列表进行排序。
编辑: Java不是我的强项(我通过交易我是SeeSharper),但代码可能看起来像:
Collections.sort(listA);
Collections.sort(listB);
ListIterator<String> aIter = listA.listIterator();
ListIterator<String> bIter = listB.listIterator();
List<String> listC = new List<String>();
while(aIter.hasNext() || bIter.hasNext())
{
if(!bIter.hasNext())
listC.add(aIter.next());
else if(!aIter.hasNext())
listC.add(bIter.next());
else
{
//kinda smells from a C# background to mix the List and its Iterator,
//but this avoids "backtracking" the Iterators when their value isn't selected.
String a = listA[aIter.nextIndex()];
String b = listB[bIter.nextIndex()];
if(a==b)
{
listC.add(aIter.next());
listC.add(bIter.next());
}
else if(a.CompareTo(b) < 0)
listC.add(aIter.next());
else
listC.add(bIter.next());
}
}