Bir alphabeTrie yapın


31

Aşağıdaki alfabetik olarak sıralanmış kelime listesini göz önünde bulundurun:

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

Tüm kelimeler ile başlar bve ilk 5 ile başlar bal. Sadece ilk 2 kelimeye bakarsak:

balderdash
ballet

bunun yerine yazabiliriz:

balderdash
  +let

burada ' 'bir kelimenin önceki kelime ile önek karakterini paylaştığı yerlerde kullanılır; '+'ikinci kelimenin önceki kelimeyle bir öneki paylaştığı SON karakterini gösteren karakter hariç .

Bu bir tür 'trie' görselleştirmesidir: ebeveyn ' bal' ve 2 soyundan oluşur: 'derdash've 'let'.

Gibi uzun bir liste ile:

balderdash
ballet
brooding

'|'paylaşılan ön ekin bittiği yerde aşağıdaki gibi daha net olması için pipe karakterini kullanabiliriz :

balderdash
| +let
+rooding

ve eşdeğer ağaç bir kök olurdu 'b'iki çocuk sahibi: alt ağacı olan kök 'al've ve iki çocuk 'derdash've 'let'; ve 'rooding'.

Bu stratejiyi orijinal listemize uygularsak,

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

Gibi görünen çıktı elde ediyoruz:

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

Listedeki iki ardışık kelimenin paylaşılan öneki yoksa, özel karakterler kullanılmaz; örneğin, liste için:

broom
brood
crude
crumb

Çıktıyı istiyoruz:

broom
   +d
crude
  +mb

Giriş

Girişteki kelimeler sadece alfanümeriklerden oluşacaktır (boşluk veya noktalama işareti içermez); Bu, seçtiğiniz formatı belirlediğiniz sürece, bir dizelerin listesi, tek bir dize veya başka bir makul yaklaşım biçiminde olabilir. İki ardışık kelime aynı olamaz. Liste alfabetik olarak sıralanacaktır.

Çıktı

Çıktınız, satır başına veya toplamda izleyen boşluk içerebilir, ancak satır aralığı boşluk bırakmaz. Bir dize listesi veya benzeri de kabul edilebilir.

Bu ; Her dilde en kısa kod, palavra haklarını saklı tutar. Boşluklara karşı normal yasaklar uygulanır.

Test Kılıfları

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 

Peki ya ballsonradan bahsettiğim dava balloon? Hangi çıktıyı beklemeliyiz?
Don

@RushabhMehta Sanırım sadece +birincisinin altında olacaktı o, ama zoru yazmadım, bu yüzden emin değilim.
Theo

5
@RushabhMehta Kelimeler alfabetik olarak sıralanır, bu yüzden bu olmaz.
Neil

@Neil Oh iyi nokta
Don Bin

2
Girişteki kelimeler sadece alfanümeriklerden oluşacaktır : bu gerçekten rakamları içerir mi, yoksa alfabetik mi demek istedin?
Arnauld,

Yanıtlar:


11

Retina 0.8.2 , 58 57 bayt

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

Çevrimiçi deneyin! Link bir test durumu içerir. Düzenleme: @FryAmTheEggman için Kayıtlı 1 bayt sayesinde ben bir geçiş gözardı olduğunu işaret \betmek ^mümkün hale m). Açıklama:

m)

^Tüm program için satır başına açın .

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

Her kelime için, önceki kelimenin başından itibaren mümkün olduğunca eşleştirmeye çalışın. Eşleşmeyi boşluklar olarak değiştirin, ki bu, a olan son karakter hariç +.

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

Tüm boşlukları hemen +s veya |s'nin hemen üzerindeki s ile değiştirin |.


@FryAmTheEggman Gerçekten, bunu m)yapabilmek için özellikle ekledim , bu yüzden bir örneği kaçırdığım için çok sinirleniyorum.
Neil

Ah, neden insanlar onları silmek için gidiyorsa neden yorumlara cevap vermekte bile
Neil

9

JavaScript (ES6), 128 bayt

Karakter listelerini bekler ve listeler.

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

Çevrimiçi deneyin!

Nasıl?

Boşluklar ve +sıralar ilk kelimeden son kelimeye doğru sırayla yürürken eklenebilir, ancak |yalnızca bir tanımlandıktan sonra bir posteriori eklenebilir +. Bu, iki farklı geçiş yaparak başarılabilir, ancak bunun yerine, değiştirilen her girişe bir gösterici kaydederiz, a[~y]böylece daha sonra aynı map()döngü içinde tekrar güncellenebilir .

Teoride, basit bir geçici çözüm, kelimeler arasında ters sırayla dolaşmak ve işlemin sonunda da çıktıyı tersine çevirmek olacaktır. Ancak bu JS'de biraz pahalı ve bu yöntemle daha kısa bir sürüm elde etmenin bir yolunu bulamadım.

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

benim çözümüme bakar mısın, kendim buldum ama çözümünü hatırlatıyor. bu yüzden çok yakınsa sizinkini gönderebilir (veya göndermeyebilir) ve hasta silebilirsiniz :)
DanielIndie

@DanielIndie Endişeye gerek yok. Yeterince farklı.
Arnauld


1

Python, 263 260 bayt

- Jonathan Frech sayesinde 3 bayt

Kod:

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)

Çevrimiçi Deneyin!

Açıklama:

Bu çözüm, girilen kelimelerin bir kısmını oluşturur ve tekrar tekrar istenen çıktıya ayrıştırır. Bir fonksiyon t ve t dizesini alır ve x'e t ekler. Denemeler iç içe sözlükler olarak uygulanır. Her sözlük, çaydaki bir düğümü temsil ediyor. Örneğin, ilk test senaryosunda oluşturulan bilgileri temsil eden sözlük şöyle görünür:

{'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 fonksiyonu bu yapı boyunca tekrar başlar ve meydan okumadan beklenen trie dizilimini gösterir. F işlevi argüman olarak bir dizi dizeyi alır, hepsini a ile bir trieğe ekler, ardından t'yi çağırmanın sonucunu döndürür.


1
Muhtemel 252 bayt .
Jonathan Frech

1

C (gcc) , 165 155 bayt

Üç argüman alır:

  • char** a : boş sonlandırılmış kelimeler dizisi
  • char* m : her kelimenin uzunluğunun bir dizisi
  • int n : dizideki kelimelerin sayısı
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;}

Çevrimiçi deneyin!



@Arnauld Elbette! Her ne kadar ++i<n&j<m[i]&a[i--]tanımsız davranış olmasa da ? Soldan sağa değerlendirmede gcc'ye güvenebilir miyim?
Curtis Bechtel

Tanımlanmamış davranış olması çok muhtemeldir. Ancak, dillerini onların uygulaması ile tanımlıyoruz, bu nedenle gcc'nin bu sürümüyle tutarlı bir şekilde çalıştığı sürece, bunun iyi olduğunu düşünüyorum.
Arnauld,

1

Perl 6 , 149 144 142 bayt

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

Çevrimiçi deneyin!

Eminim bu daha çok golf oynayabilir, özellikle regex konusunda uzman değilim. Bu, Neil'in Retina cevabı ile aynı işlemi kullanıyor .


0

Python 2 , 191 bayt

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

Çevrimiçi deneyin!


0

Ruby , 118 bayt

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

Çevrimiçi deneyin!

Dizelerin bir dizisini kabul eder, orijinal giriş dizisini yerinde değiştirerek çıkarır.

açıklama

Temel dize dönüşümü çok karmaşık değildir, ancak dikey boruları doğru şekilde yerleştirmek için ters sırayla yinelememiz gerekir ve reverseyöntem oldukça ayrıntılı olduğundan, daha zorlu bir şekilde yapacağız. Burada mapsadece döngüyü çalıştırmak için kullanırız , ilk kelimeyi yalnız bırakırız ve sonra negatif endeksleri kullanarak en baştan tekrar eder:

->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 +
 }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.