Что означает условие задачи "без дополнительной памяти"
Что проверяют
Понимаете ли вы, что это требование к асимптотике по памяти, а не пожелание экономить. Заодно смотрят, умеете ли работать со структурами на месте и видите ли скрытые аллокации, которых в Swift хватает.
Как отвечать
Формулировка означает O(1) дополнительной памяти: сколько бы ни был велик вход, алгоритм обходится фиксированным числом переменных. Сам вход и обязательный результат в эту оценку обычно не входят, но уточнить стоит: разрешено ли менять входной массив, потому что от ответа зависит решение целиком.
Типовые приёмы: два указателя навстречу друг другу (разворот, проверка палиндрома), быстрый и медленный указатели (цикл в списке, поиск середины), обмен элементов на месте, счётчики и битовые маски вместо множеств, запись промежуточных сумм поверх исходного массива.
var a = [1, 2, 3, 4]
var i = 0, j = a.count - 1
while i < j { a.swapAt(i, j); i += 1; j -= 1 }Отдельно про Swift: Array(str), map, filter и sorted создают новую коллекцию, а reversed() у массива возвращает ленивое представление и памяти не занимает. Массивы и строки работают по схеме copy-on-write, поэтому присваивание ещё не копия, копия появляется при первой записи в любую из переменных.
Где спотыкаются
Пишут рекурсивное решение и называют его решением без дополнительной памяти. Кадры лежат в стеке, и обход списка рекурсией стоит O(n), а обход дерева O(h). Если ограничение жёсткое, нужен итеративный вариант или явный стек с оговоркой.
Считают, что запрет распространяется только на массивы, и заводят словарь «на пару ключей». Постоянной считается память, которая не растёт вместе с входом, а множество уникальных элементов растёт вместе с ним.
Забывают про особенности строки в Swift. Она не поддерживает изменение элементов на месте, разворот через swapAt к ней неприменим, а перевод в массив символов ради индексации по числу это ровно та линейная память, которую просили не тратить. Про это ограничение лучше сказать вслух, чем молча скопировать строку.