Ответ
Временная сложность: O(n), где n — количество элементов в списке. Алгоритм проходит по списку ровно один раз. Пространственная сложность: O(1) дополнительной памяти при in-place модификации.
Алгоритм «двух указателей» (in-place):
Это оптимальное решение для отсортированного ArrayList.
public int removeDuplicatesFromSortedList(List<Integer> sortedList) {
if (sortedList == null || sortedList.isEmpty()) {
return 0;
}
int writeIndex = 1; // Указатель для записи уникальных элементов
for (int readIndex = 1; readIndex < sortedList.size(); readIndex++) {
// Сравниваем текущий элемент с последним записанным уникальным
if (!sortedList.get(readIndex).equals(sortedList.get(writeIndex - 1))) {
sortedList.set(writeIndex, sortedList.get(readIndex));
writeIndex++;
}
}
// Возвращаем новый размер. Элементы после writeIndex считаются «удаленными».
return writeIndex;
}
Ключевые моменты:
- Условие: Список должен быть отсортирован, иначе алгоритм не сработает.
- Поведение: Алгоритм сохраняет относительный порядок элементов.
- Для
LinkedList: Сложность по времени остается O(n), но операцииgetиsetимеют сложность O(n) каждая, что делает реализацию неэффективной. ДляLinkedListлучше использовать итератор. - Альтернатива (не in-place): Использование
LinkedHashSetсохранит порядок, но потребует O(n) дополнительной памяти.
Ответ 18+ 🔞
Да ты посмотри, какой народ безмозглый, блядь! Опять принесли отсортированный список, а там дохуя дублей, как ядрёна вошь. Ну, в рот меня чих-пых, надо их вычистить, чтобы один элемент — один, как ёбаный гвоздь в стену!
Так, слушай сюда, а не то вилкой в глаз! Задача-то проще пареной репы, если список уже по полочкам разложен. Берём два указателя, как два хуя с горы. Один (readIndex) бежит вперёд и смотрит, что там за хуйня. Второй (writeIndex) — это наш писака, он отмечает, куда класть следующий уникальный кусок.
Начинаем с единицы, потому что первый элемент — он и в Африке уникальный, его трогать не надо. Дальше простая логика, э, бошка, думай: если текущий элемент НЕ равен тому, что мы уже записали как последний уникальный (writeIndex - 1), значит, это новый чувак! Хуяк — переписываем его на место писаки и двигаем писаку дальше.
Вот и весь алгоритм, ёпта! Сложность — O(n), пробежались один разок, как мартышка по лиане. Памяти дополнительной — O(1), потому что мы жульничаем прямо в том же списке, in-place, как хитрая жопа.
public int removeDuplicatesFromSortedList(List<Integer> sortedList) {
if (sortedList == null || sortedList.isEmpty()) {
return 0;
}
int writeIndex = 1;
for (int readIndex = 1; readIndex < sortedList.size(); readIndex++) {
if (!sortedList.get(readIndex).equals(sortedList.get(writeIndex - 1))) {
sortedList.set(writeIndex, sortedList.get(readIndex));
writeIndex++;
}
}
return writeIndex;
}
Важные нюансы, а то опять накосячите:
- Список должен быть отсортирован! Иначе это пиздец, а не алгоритм. Он сравнивает только с соседом, а если дубль в другом конце — не увидит, полупидор.
- Для
LinkedListэта реализация — сосалка! Потому чтоgetиsetу него — это O(n) операция, и получится уже O(n²), волнение ебать! Для связного списка берите итератор и работайте с ним, а не с индексами, как лохи. - Если похуй на память, можно тупо запихнуть всё в
LinkedHashSet— он и порядок сохранит, и дубли выкинет. Но это O(n) доп. памяти, а мы тут не миллиардеры, чтобы память разбрасывать.
Вот так вот, на хуй. Берёшь и делаешь. А не сделаешь — Муму утоплю, блядь!