Buat alphabeTrie

31

Pertimbangkan daftar kata yang diurutkan berdasarkan abjad berikut:

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

Semua kata mulai dengan b, dan 5 pertama mulai dengan bal. Jika kita hanya melihat 2 kata pertama:

balderdash
ballet

kita bisa menulis:

balderdash
  +let

di mana ' 'digunakan di mana kata berbagi karakter awalan dengan kata sebelumnya; kecuali untuk '+'karakter yang menunjukkan karakter TERAKHIR di mana kata kedua berbagi awalan dengan kata sebelumnya.

Ini adalah semacam visualisasi 'trie' : induknya adalah ' bal', dan memiliki 2 keturunan: 'derdash'dan 'let'.

Dengan daftar yang lebih panjang, seperti:

balderdash
ballet
brooding

kita juga dapat menggunakan karakter pipa '|'untuk membuatnya lebih jelas di mana awalan bersama berakhir, sebagai berikut:

balderdash
| +let
+rooding

dan pohon yang setara akan memiliki akar 'b'memiliki dua anak: pohon itu memiliki akar 'al'dan dan dua anaknya 'derdash'dan 'let'; dan 'rooding'.

Jika kami menerapkan strategi ini ke daftar asli kami,

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

kami mendapatkan output yang terlihat seperti:

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

Jika dua kata berurutan dalam daftar tidak memiliki awalan bersama, tidak ada karakter khusus yang diganti; misalnya untuk daftar:

broom
brood
crude
crumb

kami ingin output:

broom
   +d
crude
  +mb

Memasukkan

Kata-kata dalam input hanya terdiri dari alfanumerik (tanpa spasi atau tanda baca); ini mungkin dalam bentuk daftar string, string tunggal, atau pendekatan masuk akal lainnya, selama Anda menentukan format yang Anda pilih. Tidak ada dua kata berurutan yang akan sama. Daftar ini akan disortir berdasarkan abjad.

Keluaran

Output Anda dapat berisi spasi spasi per baris atau total, tetapi tidak ada spasi putih terkemuka. Daftar string atau yang serupa juga akan diterima.

Ini adalah ; kode terpendek di setiap bahasa tetap memiliki hak untuk menyombongkan diri. Larangan biasa terhadap celah berlaku.

Uji Kasus

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 
Chas Brown
sumber
Bagaimana dengan kasus di mana saya memiliki kata ballsetelah balloon. Output apa yang harus kita harapkan?
Don Thousand
@RushabhMehta Saya kira Anda hanya akan memiliki di +bawah yang pertama o, tapi saya tidak menulis tantangan jadi saya tidak yakin.
Theo
5
@RushabhMehta Kata-kata diurutkan berdasarkan abjad, jadi ini tidak akan terjadi.
Neil
@Neil Oh good point
Don Thousand
2
Kata-kata dalam input hanya terdiri dari alfanumerik : apakah itu benar-benar termasuk digit, atau maksud Anda alfabet?
Arnauld

Jawaban:

11

Retina 0.8.2 , 58 57 byte

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

Cobalah online! Tautan mencakup satu test case. Edit: Disimpan 1 byte berkat @FryAmTheEggman menunjukkan bahwa saya diabaikan beralih dari \bke ^dimungkinkan oleh m). Penjelasan:

m)

Aktifkan per-line ^untuk seluruh program.

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

Untuk setiap kata, cobalah untuk mencocokkan sebanyak mungkin dari awal kata sebelumnya. Ubah kecocokan menjadi spasi, kecuali karakter terakhir, yang menjadi a +.

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

Ganti semua ruang secara berulang tepat di atas +s atau |s dengan |s.

Neil
sumber
@FryAmTheEggman Memang, saya menambahkan m)secara khusus untuk dapat melakukan itu, jadi saya kesal karena saya melewatkan sebuah instance.
Neil
Ugh, mengapa saya bahkan repot-repot membalas komentar jika orang hanya akan menghapusnya ...
Neil
9

JavaScript (ES6), 128 byte

Mengharapkan dan mengembalikan daftar daftar karakter.

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)))

Cobalah online!

Bagaimana?

Spasi dan +'s dapat dimasukkan dengan berjalan melalui kata pertama ke kata terakhir secara berurutan, tetapi |' s hanya dapat disisipkan posteriori setelah a +telah diidentifikasi. Ini dapat dicapai dengan melakukan dua lintasan yang berbeda, tetapi sebaliknya kami menyimpan pointer ke setiap entri yang dimodifikasi a[~y]sehingga nanti dapat diperbarui lagi dalam map()loop yang sama .

Secara teori, solusi yang lebih sederhana adalah berjalan melalui kata-kata dalam urutan terbalik dan membalik output juga pada akhir proses. Tapi ini agak mahal di JS dan saya tidak menemukan cara untuk mendapatkan versi yang lebih pendek dengan metode ini.

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
Arnauld
sumber
Anda akan melihat solusi saya, saya datang dengan itu sendiri tetapi mengingatkan solusi Anda. jadi jika terlalu dekat Anda dapat mengirimkannya sebagai milik Anda (atau tidak) dan tidak akan menghapusnya :)
DanielIndie
@DanielIndie Jangan khawatir. Cukup berbeda.
Arnauld
2

JavaScript (Node.js) , 125 122 118 117 byte

a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))

Cobalah online!

  • terima kasih kepada @Arnauld untuk pengujian tio :)
DanielIndie
sumber
1

Python, 263 260 byte

- 3 byte terima kasih kepada Jonathan Frech

Kode:

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)

Cobalah secara Online!

Penjelasan:

Solusi ini membangun trie dari kata-kata input dan mem-parsing secara rekursi ke dalam output yang diperlukan. Fungsi a mengambil trie t dan string s dan menambahkan x ke t. Mencoba diimplementasikan sebagai kamus bersarang. Setiap kamus mewakili sebuah simpul dalam trie. Misalnya, kamus yang mewakili trie yang dihasilkan oleh test case pertama terlihat seperti ini:

{'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': {}}}}}}

Fungsi p berulang melalui struktur ini dan menghasilkan representasi string dari trie yang diharapkan oleh tantangan. Fungsi f mengambil banyak string sebagai argumen, menambahkan semuanya ke sebuah trie dengan a, lalu mengembalikan hasil memanggil p pada trie.

Zachary Cotton
sumber
1
Kemungkinan 252 byte .
Jonathan Frech
1

C (gcc) , 165 155 byte

Membawa tiga argumen:

  • char** a : array kata-kata yang diakhiri nol
  • char* m : array panjang setiap kata
  • int n : jumlah kata dalam array
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;}

Cobalah online!

Curtis Bechtel
sumber
@Arnauld Tentu saja! Meskipun bukankah ++i<n&j<m[i]&a[i--]perilaku tidak terdefinisi? Bisakah saya mengandalkan gcc untuk mengevaluasinya dari kiri ke kanan?
Curtis Bechtel
Sangat mungkin perilaku yang tidak terdefinisi. Tapi kami mendefinisikan bahasa dengan implementasinya, jadi selama itu bekerja secara konsisten dengan versi gcc ini, saya pikir itu bagus.
Arnauld
1

Perl 6 , 149 144 142 byte

{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("
")}

Cobalah online!

Saya yakin ini bisa bermain golf lebih, terutama karena saya bukan ahli regex. Ini menggunakan banyak proses yang sama dengan jawaban Neil's Retina .

Jo King
sumber
0

Python 2 , 191 byte

def f(w,r=['']):
 for b,c in zip(w[1:],w)[::-1]:
	s='';d=0
	for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
	r=[s]+r
 return[w[0]]+r

Cobalah online!

Chas Brown
sumber
0

Ruby , 118 byte

->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/]&&=?+}}

Cobalah online!

Menerima larik string, menghasilkan output dengan memodifikasi larik input asli di tempat.

Penjelasan

Transformasi string dasar tidak terlalu rumit, tetapi untuk memasukkan pipa vertikal dengan benar, kita perlu beralih dalam urutan terbalik, dan karena reversemetode ini cukup bertele-tele, kita akan melakukannya dengan cara yang lebih rumit. Di sini, kami menggunakan maphanya untuk menjalankan loop, biarkan kata pertama saja, dan kemudian beralih dari akhir menggunakan indeks negatif:

->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 +
 }
}
Kirill L.
sumber