如何在Java中合并一个排序列表中的两个大列表?

时间:2012-09-05 19:34:38

标签: java performance list

我今天接受了采访,他们给了我:

列表A有:

f  
google   
gfk  
fat  
...

列表B有:

hgt    
google  
koko  
fat  
ffta  
...

他们让我将这两个列表合并到一个已排序的列表C中。

我说的是:

我将List B添加到List A,然后我从List A创建了一个Set,然后从Set创建一个List。面试官告诉我这些名单很大,这种方法对表现不利,他说这将是一个nlog(n)。

对这个问题有什么更好的解决方法?

1 个答案:

答案 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());          
   }
}