alphabeTrieを作成する


31

次のアルファベット順にソートされた単語のリストを検討してください。

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

すべての単語はで始まりb、最初の5つはで始まりbalます。最初の2つの単語だけを見ると:

balderdash
ballet

代わりに書くことができます:

balderdash
  +let

ここ' 'で、単語が前の単語と接頭辞文字を共有する場所で使用されます。'+'2番目の単語が前の単語と接頭辞を共有する最後の文字を示す文字を除きます。

これは一種の「トライ」視覚化です。親は「bal」であり、2つの子孫が'derdash'あり'let'ます。

次のような長いリストの場合:

balderdash
ballet
brooding

さらに、パイプ文字'|'を使用して、次のように共有プレフィックスの末尾を明確にすることができます。

balderdash
| +let
+rooding

そして、同等の木は根のだろう'b'2人の子供持つ:サブツリーたルート'al'と、その2人の子供'derdash'とを'let'、および'rooding'

この戦略を元のリストに適用すると、

balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom

次のような出力が得られます。

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

リスト内の2つの連続した単語に共有プレフィックスがない場合、特殊文字は置換されません。例えばリストの場合:

broom
brood
crude
crumb

出力が必要です:

broom
   +d
crude
  +mb

入力

入力内の単語は英数字のみで構成されます(スペースや句読点は含まれません)。これは、選択した形式を指定する限り、文字列のリスト、単一の文字列、またはその他の合理的なアプローチの形式になります。2つの連続した単語が同じになることはありません。リストはアルファベット順にソートされます。

出力

出力には、行ごとまたは合計で末尾の空白を含めることができますが、先頭の空白は含まれません。文字列のリストなども受け入れられます。

これはです。各言語の最短コードは自慢する権利を保持します。抜け穴に対する通常の禁止が適用されます。

テストケース

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.258の 57バイト

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

オンラインでお試しください!リンクには1つのテストケースが含まれます。編集:保存された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)))

オンラインでお試しください!

どうやって?

スペースとを+挿入するには、最初の単語から最後の単語まで順番に移動しますが、を|挿入できるのは、識別された後の事後記号のみ+です。これは、2つの別個のパスを実行することで実現できますが、代わりに、変更された各エントリへのポインタを保存して、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心配いりません。それは十分に異なっています。
アーナルド


1

Python、263 260バイト

- 3は、ジョナサンFRECHのおかげでバイト

コード:

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

C(gcc)165 155バイト

3つの引数を取ります。

  • char** a :nullで終わる単語の配列
  • 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と一貫して機能する限り、それで問題ないと思います。
アーナルド



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 +
 }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.