Блог пользователя maximumSHOT

Автор maximumSHOT, история, 9 лет назад, По-русски

Привет всем! Хотел узнать за сколько (асимптотика) работает сортировка строк следующим образом?

int n;
vector< string > a(n);
sort(a.begin(), a.end());

Будем считать, что все строки имеют длину от 1 до 1e5 и сумма длин всех строк не превышает 2e5. 1 <= sumLen <= 2e5

Количество строк от 1 до 1е5. 1 <= n <= 1e5

P.S. Известно, что существует сортировка строк за время O(sumLen) и O(sumLen * k) памяти или

за время O(sumLen * log(K)) и O(sumLen) памяти с помощью бора, но хотелось бы

разобраться с более короткой версией (с точки зрения написания кода). Заранее Спасибо!

  • Проголосовать: нравится
  • +35
  • Проголосовать: не нравится

»
9 лет назад, # |
Rev. 2   Проголосовать: нравится -58 Проголосовать: не нравится

не подумав сказанная дичь...

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится

    Такая сортировка даст нам строку, образованную конкатенацией наших строк в одну, причем такая строка будет лексикографически минимальной, а нам нужно отношение наших строк между собой.

    Контрпример: b и ba : bba > bab, но b < ba

»
9 лет назад, # |
  Проголосовать: нравится +30 Проголосовать: не нравится

O(sumLen * log(n)), и вот почему.

Предположим сначала, что все строки имеют одинаковую длину L, тогда sumLen = n * L. std::sort делает O(n * log(n)) сравнений, каждое сравнение делается за O(L). Получается сортировка за O(nL log(n)) = O(sumLen log(n)).

Если же длины строк разные, то получится даже меньше операций, так как при сравнении длинной строки с короткой на последние символы длинной мы никогда не посмотрим.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Что касается памяти, говорят, что стандартом это не ограничивается. На практике используемый алгоритм сортировки и, соответственно, потребление памяти зависят от входных данных, но здравый смысл подсказывает, что вряд ли реализации понадобится использовать больше памяти, чем на поддержание перестановки O(n) итераторов или на стек рекурсии глубиной O(n).

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +20 Проголосовать: не нравится

    Допустим, у нас n - 2 строки длины 1 и две строки длины k. Сходу неочевидно, что мы не получим слишком много сравнений больших строк друг с другом. И, кажется, чтобы доказать, что это , нужно опираться на то, что сортировка в C++ применяется именно introsort.

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Я тоже раньше этот факт только для Quick-Sort и модификаций доказывал... Забавно, вроде для MergeSort и HeapSort тоже верно. Интересно, есть хотя бы одна реальная nlogn сортировка, которая слишком долго сортит строки? =)

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        А что такое "реальная"? :)

        • »
          »
          »
          »
          »
          9 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          По крайней мере не та, в которой стоит if на то, что если сортируемые элементы строки — то сортировать пузырьком :D

          • »
            »
            »
            »
            »
            »
            9 лет назад, # ^ |
              Проголосовать: нравится 0 Проголосовать: не нравится

            А если сортировка просто в конце делает O(n) сравнений последних двух элементов, чтобы убедиться, что они отсортированы, она реальная или уже нет? :)

            В отличие от пузырька всё же она делает сравнений всегда

        • »
          »
          »
          »
          »
          9 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Мы можем в любую nlogn сортировку вставить n сравнений первых двух элементов, от этого она останется nlogn и станет TL-иться на твоём примере. Но это искусственно созданная сортировка. Реальная -- в смысле, не искусственно испорченная, и за nlogn.

»
9 лет назад, # |
Rev. 2   Проголосовать: нравится -23 Проголосовать: не нравится

Можно сортирвку за O(N * logN * logM). N — кол-во строк, M — длина макс. строки. Считаем хэш всех строк, и когда сравниваем 2 строки, используем бинпоиск. То есть общий префикс будет иметь равный хэш, а вот следующий символ будет отличаться.