Какова временная сложность удаления дубликатов из отсортированного списка в Java

Ответ

Временная сложность: 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) доп. памяти, а мы тут не миллиардеры, чтобы память разбрасывать.

Вот так вот, на хуй. Берёшь и делаешь. А не сделаешь — Муму утоплю, блядь!