Лексикографическая сортировка

Я делаю проблему, которая говорит: "объедините слова, чтобы создать лексикографически минимально возможную строку.- с конкурса.

возьмите, например, эту строку:jibw ji jp bw jibw

фактический выход оказывается:bw jibw jibw ji jp

когда я делаю сортировку на этом, я получаю:bw ji jibw jibw jp.

значит ли это, что это не сортировка? Если это сортировка, "лексикографическая" сортировка учитывает нажатие более коротких строк назад или что-то?

Я делал некоторые чтения на порядок lexigographical и я не вижу никакой точки или сценариев, на которых это используется, у вас есть?

10 ответов


Кажется, что то, что вы ищете более глубокое понимание вопроса, поэтому позвольте мне сделать это ясно. Обычная сортировка по строкам и лексикографической сортировки. Если отсортировать строки [jibw, ji, jp, bw, jibw] в лексикографическом порядке, отсортированная последовательность и [bw, ji, jibw, jibw, jp], что у вас есть. Таким образом, ваша проблема не в понимании слова "лексикографический"; вы уже понимаете его правильно.

ваша проблема в том, что ты неправильно понял вопрос. Вопрос не просит вас вроде строки в лексикографическом порядке. (Если бы это было так, ответ, который вы получили путем сортировки, был бы правильным.) Вместо этого, он просит вас произвести один string, got by объединения входные строки в некотором порядке (т. е. создание одной строки без пробелов), так что результирующая одиночная строка лексикографически минимальна.

чтобы проиллюстрировать разницу, рассмотрим строку вы объединение отсортированной последовательности и строки ответа:

bwjijibwjibwjp //Your answer
bwjibwjibwjijp //The correct answer

теперь, когда вы сравните эти две строки - обратите внимание, что вы просто сравниваете две 14-символьные строки, а не две последовательности строк - можно увидеть, что правильный ответ-это действительно лексикографически меньше, чем ваш ответ: ваш ответ начинается с "bwjij", а правильный ответ начинается с "bwjib", и "bwjib" идет перед "bwjij" в лексикографическом порядке.

надеюсь, вы понимаете теперь вопрос. Он это вообще не вопрос сортировки. (То есть, это не проблема сортировки входных строк. Вы может сортировка по всем возможным строкам, полученным путем перестановки и конкатенации входных строк; это один из способов решения проблемы, если количество входных строк мало.)


вы можете преобразовать это в тривиальную проблему сортировки, сравнивая word1 + word2 против word2 + word1. В Python:

def cmp_concetanate(word1, word2):
    c1 = word1 + word2
    c2 = word2 + word1
    if c1 < c2:
        return -1
    elif c1 > c2:
        return 1
    else:
        return 0

использование этой функции сравнения со стандартной сортировкой решает проблему.


я использовал F# в этом Кубке хакеров Facebook. Многому научился в этом соревновании. Поскольку документация по F# в интернете все еще редка, я думаю, что я мог бы также поделиться немного здесь.

эта проблема запрашивает сортировку списка строк на основе настраиваемого метода сравнения. Вот мой фрагмент кода в F#.


    let comparer (string1:string) (string2:string) =
         String.Compare(string1 + string2, string2 + string1)

    // Assume words is an array of strings that you read from the input
    // Do inplace sorting there
    Array.sortInPlaceWith comparer words
    // result contains the string for output
    let result = Array.fold (+) "" words


/ / используйте этот блок кода для печати лексикографически отсортированных символов массива или его можно использовать многими способами.

  #include<stdio.h>
  #include<conio.h>

  void combo(int,int,char[],char[],int*,int*,int*);

  void main()
  {
      char a[4]={'a','b','c'};
      char a1[10];
      int i=0,no=0;
      int l=0,j=0;
      combo(0,3,a,a1,&j,&l,&no);
      printf("%d",no);
      getch();
  }
  void combo(int ctr,int n,char a[],char a1[],int*j,int*l,int*no)
  {
      int i=0;
      if(ctr==n)
      {
        for(i=0;i<n;i++)
            printf("%c",a1[i]);
        printf("\n");
        (*no)++;
        (*j)++;
        if((*j)==n)
        { 
            *l=0;
             *j=0;
        }
        else
        *l=1;       
        getch();
      }
      else
        for(i=0;i<n;i++)
        {
        if(*l!=1)
            *j=i;
        a1[ctr]=a[*j];
        combo(ctr+1,n,a,a1,j,l,no);
        }
    }

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

фактический выход не нарушает условия для лексикографически самого низкого слова.


команда сортировки в linux также выполняет Лексикографическую сортировку и генерирует вывод в порядке BW ji jibw jibw jp


проверьте, что здесь произошло:

Если вы просто примените лексикографическую сортировку, вы получите BW ji jibw jibw jp но если разбирать маркер на маркер вы увидите, что "bwjibw" (БВ, jibw) является lexicographicaly ниже, чем "bwjijibw" (ЖВ, жи, jibw) поэтому ответ БВ jibw jibw Джи ДЖП ведь сначала нужно добавить bwjibwjibw и после этого вы смогли соединить со и JP, чтобы получить самую низкую строку.


простой трюк, включающий только сортировку, которая будет работать для этой проблемы, поскольку указана максимальная длина строки, будет заключаться в заполнении всех строк до максимальной длины первой буквой в строке. Затем вы сортируете проложенные строки, но выводите исходные непакованные. Для экс. для длины строки 2 и входов b и ba вы сортируете bb и ba, которые дадут вам ba и bb, и, следовательно, вы должны вывести bab.


трюк Прасуна работает, если вместо этого вы добавляете специальный символ "заполнитель", который может быть взвешен больше, чем" z " в функции сортировки строк. Результат даст вам порядок наименьшей лексикографической комбинации.


конкурс закончился, поэтому я публикую возможное решение, не самое эффективное, но один из способов сделать это

 #include <iostream>
 #include <fstream>
 #include <string>
    #include <algorithm>
    using namespace std;
   int main()
  {
ofstream myfile;
myfile.open("output.txt");
int numTestCases;
int numStrings;
string* ptr=NULL;
char*ptr2=NULL;
string tosort;
scanf("%d",&numTestCases);
for(int i=0;i<numTestCases;i++)
{
    scanf("%d",&numStrings);
    ptr=new string[numStrings];
    for(int i=0;i<numStrings;i++)
    {
        cin>>ptr[i];
    }
    sort(ptr,ptr+numStrings);
    for(int i=0;i<numStrings;i++)
    {
        next_permutation(ptr,ptr+numStrings);
    }
    tosort.clear();
    for(int i=0;i<numStrings;i++)
    {
        tosort.append(ptr[i]);
    }
    ptr2=&tosort[i];

    cout<<tosort<<endl;
    myfile<<tosort<<endl;   
    delete[]ptr;
}
return 0;
  }

Я использую алгоритмы из библиотеки STL в C++, функция prev_permutation просто генерирует перестановку, отсортированную лексикографически