Сделайте alphabeTrie


31

Рассмотрим следующий отсортированный по алфавиту список слов:

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

Все слова начинаются с b, а первые 5 начинаются с bal. Если мы просто посмотрим на первые 2 слова:

balderdash
ballet

мы могли бы написать вместо этого:

balderdash
  +let

где ' 'используется, когда слово разделяет префиксный символ с предыдущим словом; за исключением '+'символа, который указывает последний символ, где второе слово имеет префикс с предыдущим словом.

Это своего рода визуализация "trie" : родительский объект имеет ' bal' и имеет 2 потомка: 'derdash'и 'let'.

С более длинным списком, таким как:

balderdash
ballet
brooding

мы можем дополнительно использовать символ канала, '|'чтобы прояснить, где заканчивается общий префикс, следующим образом:

balderdash
| +let
+rooding

и эквивалентное дерево будет иметь корень, 'b'имеющий два дочерних элемента : поддерево, имеющее корень, 'al'и его два дочерних элемента 'derdash'и 'let'; и 'rooding'.

Если мы применим эту стратегию к нашему первоначальному списку,

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

мы получаем вывод, который выглядит так:

balderdash    
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m 

Если два последовательных слова в списке не имеют общего префикса, никакие специальные символы не подставляются; например, для списка:

broom
brood
crude
crumb

мы хотим вывод:

broom
   +d
crude
  +mb

вход

Слова на входе будут состоять только из буквенно-цифровых символов (без пробелов и знаков препинания); это может быть в форме списка строк, отдельной строки или любого другого разумного подхода, если вы указываете выбранный вами формат. Два последовательных слова не будут одинаковыми. Список будет отсортирован по алфавиту.

Выход

Ваш вывод может содержать конечные пробелы в строке или в целом, но без начальных пробелов. Список строк или аналогичных также будет приемлемым.

Это ; самый короткий код на каждом языке сохраняет права хвастовства. Обычные запреты против лазеек применяются.

Тестовые случаи

Input:
apogee
apology
app
apple
applique
apply
apt

Output:
apogee     
 |+logy    
 +p        
 |+le      
 | +ique   
 | +y      
 +t        

Input:
balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom
donald
donatella
donna
dont
dumb

Output:
balderdash 
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m      
donald     
| |+tella  
| +na      
| +t       
+umb 

Как насчет случая, когда у меня есть слово ballпосле balloon. Какой выход мы должны ожидать?
Дон Тысяча

@RushabhMehta Я полагаю, у вас будет только +первый o, но я не написал вызов, поэтому я не уверен.
Тео

5
@RushabhMehta Слова отсортированы по алфавиту, поэтому этого не произойдет.
Нил

@ Нил О, хороший момент
Дон Тысяча

2
Слова на входе будут состоять только из буквенно-цифровых символов : действительно ли они включают цифры или вы имели в виду буквенные символы?
Арно

Ответы:


11

Сетчатка 0.8.2 , 58 57 байт

^((.*).)(?<=\b\1.*¶\1)
$.2$* +
m)+`^(.*) (.*¶\1[+|])
$1|$2

Попробуйте онлайн! Ссылка включает в себя один контрольный пример. Редактировать: 1 байт сохранен благодаря @FryAmTheEggman, который указал, что я пропустил переход с \bна, ^сделанный возможным благодаря m). Объяснение:

m)

Включите каждую линию ^для всей программы.

^((.*).)(?<=^\1.*¶\1)
$.2$* +

Для каждого слова постарайтесь найти максимально возможное совпадение с начала предыдущего слова. Измените соответствие на пробелы, кроме последнего символа, который становится +.

+`^(.*) (.*¶\1[+|])
$1|$2

Повторно заменяйте все пробелы непосредственно над +s или |s на |s.


@FryAmTheEggman Действительно, я специально добавил, m)чтобы можно было это сделать, поэтому мне досадно, что я пропустил экземпляр.
Нил

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

9

JavaScript (ES6), 128 байт

Ожидает и возвращает список списков персонажей.

a=>a.map((w,y)=>a[~y]=w.map(m=(c,x)=>(p=a[y-1]||0,m|=c!=p[x])?c:p[x+1]==w[x+1]?' ':(g=y=>a[y][x]<1?g(y+1,a[y][x]='|'):'+')(-y)))

Попробуйте онлайн!

Как?

Пробелы и +'s могут быть вставлены, пройдя от первого до последнего слова по порядку, но |' s могут быть вставлены апостериори только +после идентификации a . Этого можно достичь, выполнив два разных прохода, но вместо этого мы сохраняем указатель на каждую измененную запись, a[~y]чтобы впоследствии ее можно было снова обновить в том же map()цикле.

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

a =>                           // a[] = input array
  a.map((w, y) =>              // for each word w at position y in a[]:
    a[~y] =                    //   save a pointer to the current entry in a[~y]
    w.map(m =                  //   initialize m to a non-numeric value
      (c, x) => (              //   for each character c at position x in w:
        p = a[y - 1] || 0,     //     p = previous word or a dummy object
        m |= c != p[x]         //     set m = 1 as soon as w differs from p at this position
      ) ?                      //     if w is no longer equal to p:
        c                      //       append c
      :                        //     else:
        p[x + 1] == w[x + 1] ? //       if the next characters are still matching:
          ' '                  //         append a space
        : (                    //       else:
            g = y =>           //         g() = recursive function to insert pipes
            a[y][x] < 1 ?      //           if a[y][x] is a space:
              g(               //             do a recursive call to g()
                y + 1,         //               with y + 1
                a[y][x] = '|'  //               and overwrite a[y][x] with a pipe
              )                //             end of recursive call
            :                  //           else:
              '+'              //             make the whole recursion chain return a '+'
                               //             which will be appended in the current entry
          )(-y)                //         initial call to g() with -y (this is ~y + 1)
    )                          //   end of map() over the characters
  )                            // end of map() over the words

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

@DanielIndie Не беспокойся. Это достаточно отличается.
Арно


1

Python, 263 260 байт

- 3 байта благодаря Джонатану Фреху

Код:

p=lambda t,f,g:"\n".join([(f[:-1]+"+"if(a!=min(t))*g else"")+a+p(t[a],(f+" "if len(t[a])>1or a==max(t)else f[:-1]+"| "),1)for a in t])if t else""
def a(t,x):
 if x:c=x[0];t[c]=c in t and t[c]or{};a(t[c],x[1:])
def f(*s):t={};[a(t,i)for i in s];return p(t,"",0)

Попробуйте онлайн!

Объяснение:

Это решение создает три из входных слов и рекурсивно анализирует их в требуемый выходной. Функция a принимает три t и строку s и добавляет x к t. Попытки реализованы в виде вложенных словарей. Каждый словарь представляет узел в дереве. Например, словарь, представляющий три, сгенерированный первым тестовым примером, выглядит следующим образом:

{'b': {'a': {'l': {'d': {'e': {'r': {'d': {'a': {'s': {'h': {}}}}}}}, 'l': {'e': {'t': {}}, 'o': {'o': {'n': {'f': {'i': {'s': {'h': {}}}}, 'i': {'s': {'t': {}}}}}, 't': {}}}}}, 'r': {'o': {'o': {'d': {'i': {'n': {'g': {}}}}, 'm': {}}}}}}

Функция p проходит через эту структуру и генерирует строковое представление дерева, ожидаемого вызовом. Функция f принимает несколько строк в качестве аргументов, добавляет их все в три с помощью a, а затем возвращает результат вызова p для этого три.


1
Возможные 252 байта .
Джонатан Фрех

1

C (gcc) , 165 155 байтов

Принимает три аргумента:

  • char** a : массив слов с нулем в конце
  • char* m : массив длины каждого слова
  • int n : количество слов в массиве
f(a,m,n,i,j)char**a,*m;{for(i=n;--i;)for(j=0;j<m[i]&j<m[i-1]&a[i][j]==a[i-1][j];j++)a[i][j]=a[i][j+1]^a[i-1][j+1]?43:++i<n&j<m[i]&a[i--][j]%81==43?124:32;}

Попробуйте онлайн!



@Arnauld Конечно! Хотя не ++i<n&j<m[i]&a[i--]неопределенное поведение? Могу ли я рассчитывать на gcc, оценивая его слева направо?
Кертис Бехтел

Скорее всего, это будет неопределенное поведение. Но мы определяем языки по их реализации, поэтому, если они работают согласованно с этой версией gcc, я думаю, это нормально.
Арно

1

Perl 6 , 149, 144, 142 байта

{1 while s/(\n.*)\s(.*)$0(\+|\|)/$0|$1$0$2/;$_}o{$=({.[1].subst(/^(.+)<?{.[0].index($0)eq 0}>/,{' 'x$0.ords-1~'+'})}for '',|$_ Z$_).join("
")}

Попробуйте онлайн!

Я уверен, что это может быть в гольфе больше, тем более, что я не эксперт по регулярным выражениям. Это использует тот же процесс, что и ответ Нейла на сетчатку .



0

Рубин , 118 байт

->a{i=1;a.map{s="";a[i+=j=-1].chars{|c|a[i][j+=1]=i<0&&a[i-1][/^#{s+=c}/]?a[i+1][j]=~/[|+]/??|:?\s:c}[/[| ]\b/]&&=?+}}

Попробуйте онлайн!

Принимает массив строк, выводит путем изменения исходного входного массива на месте.

объяснение

Базовое преобразование строк не слишком сложно, но для правильной вставки вертикальных каналов нам нужно выполнить итерацию в обратном порядке, и, поскольку reverseметод довольно многословен, мы сделаем это более хитрым способом. Здесь мы используем mapтолько для запуска цикла, оставляем первое слово в покое, а затем выполняем итерацию с конца, используя отрицательные индексы:

->a{
 i=1;                   #Initialize word indexer
 a.map{                 #Loop
  s="";                 #Initialize lookup string
  a[i+=j=-1]            #Initialize char indexer and decrement i
  .chars{|c|            #Loop through each char c of current word
   a[i][j+=1]=          #Mofify current word at position j 
    i<0&&               #If it's not the first word and
    a[i-1][/^#{s+=c}/]? #Word above matches current one from start to j
     a[i+1][j]=~/[|+]/? #Then if char below is | or +
      ?|:?\s:c          #Then set current char to | Else to Space Else leave as is
  }[/[| ]\b/]&&=?+      #Finally, replace Space or | at word boundary with +
 }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.