Нужно ли добавлять оставшиеся элементы из более длинного списка после слияния?
Что проверяют
Доводите ли вы алгоритм до конца и проверяете ли граничные случаи. Вопрос обычно задают ровно в тот момент, когда кандидат написал основной цикл слияния и остановился, считая задачу решённой.
Как отвечать
Ответ однозначный: добавлять обязательно. Основной цикл завершается, как только исчерпан любой из входов, а во втором остаётся хвост. Он уже отсортирован и заведомо не меньше всего, что попало в результат, поэтому дописывается целиком, без единого сравнения. Пропустить его значит молча потерять данные, и тест на входах разной длины это сразу покажет.
def merge(a, b):
res, i, j = [], 0, 0
while i < len(a) and j < len(b):
if a[i] <= b[j]:
res.append(a[i]); i += 1
else:
res.append(b[j]); j += 1
res.extend(a[i:])
res.extend(b[j:])
return resПроговорите сложность: один проход, время порядка суммы длин, столько же дополнительной памяти. И добавьте практический слой, для data-ml он уместен: руками такое пишут только на собеседовании, в работе есть heapq.merge для ленивого слияния отсортированных потоков, сортировка после конкатенации массивов, а для временных рядов merge_ordered и merge_asof в pandas, который склеивает по ближайшему времени.
Где спотыкаются
Дописывают хвост только одного списка, обычно первого. На части входов код работает правильно, и ошибка ловится не глазами, а тестом, где длиннее оказывается второй вход.
Второе: берут строгое сравнение вместо нестрогого. При равных элементах порядок между источниками переворачивается, слияние перестаёт быть устойчивым, и сортировка, построенная на нём, ломает ранее заданный порядок одинаковых ключей.
Третье: не проверяют вырожденные входы. Пустой список, один элемент, полностью непересекающиеся диапазоны. Отдельная история это слияние на месте в конец первого массива, там заполнять надо с конца, иначе затираются ещё не прочитанные элементы.