Я думаю, что это невозможно с вашими заданными ограничениями (O(n)
время и O(1)
пробел, то есть без дополнительного пробела) для массива или списка на основе массива. (Разумеется, при условии, что мы не можем просто создать новый объект List, делегирующий исходные.)
Если у вас есть два связанных списка, это выполнимо - если мы предположим, что сборщик мусора работает достаточно быстро, то есть удаление элемента из одного списка и добавление его в другой список не нарушает ограничение пространства.
public <X> void interleaveLists(List<X> first, List<X> second)
{
ListIterator<X> firstIt = first.listIterator();
ListIterator<X> secondIt = second.listIterator();
while(secondIt.hasNext()) {
fistIt.next();
firstIt.add(secondIt.next());
secondIt.remove();
}
}
Этот метод работает для любой пары списков, но для связанных списков используется только O (n).
Для настраиваемого связанного списка, в котором мы можем изменять указатели, нам не нужно полагаться на сборщик мусора, мы просто изменили бы узлы. Здесь для односвязного списка:
public void interleaveLinkedLists(Node<X> firstList, Node<X> secondList) {
while(secondList != null) {
Node<X> nextFirst = firstList.next;
Node<X> nextSecond = secondList.next;
firstList.next = secondList;
secondList.next = nextFirst;
firstList = nextFirst;
secondList = nextSecond;
}
}
Для двусвязного списка нам также придется адаптировать предыдущие указатели.
Здесь вариант обмотки, упомянутый в первом абзаце:
public List<X> interleaveLists(final List<X> first, final List<X> second)
{
if (first.size() != second.size())
throw new IllegalArgumentException();
return new AbstractList<X>() {
public int size() {
return 2 * first.size();
}
public X get(int index) {
return index % 2 == 0 ? first.get(index / 2) : second.get(index / 2);
}
// if necessary, add a similar set() method. add/remove are not sensible here.
};
}
На самом деле это тоже O(1)
во времени.