基数ツリーの高さを計算する


8

前書き

基数ツリー、圧縮トライまたは圧縮プレフィックスツリーとして知られているが、文字列の集合を記憶するツリー状のデータ構造です。ツリーのエッジは空でない文字列でラベル付けされ、各ノードは終端または非終端です。ツリーに含まれる文字列は、ルートからターミナルノードまでのすべてのパスのラベルです。ツリーは、次の条件で定義される通常の形式である必要があります。

  • すべての非終端非ルートノードには、少なくとも2つの子があります。
  • すべてのノードで、すべての発信エッジの最初の文字が異なります。

たとえば、次のセットは非終端ノードと終端ノード["test", "testing", "tested", "team", "teams", "technical", "sick", "silly"](N)表す基数ツリーです(T)

-(N)-te-(N)-st-(T)-ing-(T)
  |      |      | 
  |      |      +-ed-(T)
  |      |
  |      +-am-(T)-s-(T)
  |      |
  |      +-chnical-(T)
  |
  +-si-(N)-ck-(T)
        |
        +-lly-(T)

この課題では、入力として文字列を指定して、木の高さを計算します。

入力

入力は、小文字のASCII文字列の空でないリストです。重複は含まれませんが、どのような順序でもかまいません。空の文字列が含まれる場合があります。入力は適切な形式で取得できます。

出力

出力は、対応する基数ツリー内の最長のルートからリーフへのパスの長さで、含まれるノードの数で測定されます。

上記の例では、パスに対応する正しい出力は4です。

(N)-te-(N)-st-(T)-ing-(T)
(N)-te-(N)-st-(T)-ed-(T)
(N)-te-(N)-am-(T)-s-(T)

4つのノードを含みます。

さらなる例

基数ツリーの例をいくつか示します。

[""]
-(T)

["","fuller"]
-(T)-fuller-(T)

["","full","fuller"]
-(T)-full-(T)-er-(T)

["full","fuller"]
-(N)-full-(T)-er-(T)

["full","filler"]
-(N)-f-(N)-ull-(T)
        |
        +-iller-(T)

ルールとスコアリング

完全なプログラムまたは関数を作成できます。これはコードゴルフなので、バイト数が最も少ないものが優先されます。

必要な組み込みまたはライブラリを使用できimportますが、バイト数にはすべてのsなどを含めることを忘れないでください。サードパーティライブラリ(言語の標準インストールに含まれていないライブラリ)は許可されますが、ヘッダーに個別にリストする必要があります(例:Python + pytrie0.2、60バイト)

テストケース

[""] -> 1
["fuller"] -> 2
["","fuller"] -> 2
["","full","fuller"] -> 3
["full","fuller"] -> 3
["full","filler"] -> 3
["full","filler","filter"] -> 4
["full","filler","fi","filter"] -> 5
["test","testing","tested","team","teams","technical","sick","silly"] -> 4
["a","aaaa","aabbaa","aabbaab","abaaa","aab","aabbb","aabba"] -> 8
["dbdbaca","ab","a","caaabaaa","adbbabdb","dbdbdbaca","dbbadbacaba","db"] -> 4
["db","dbbdbb","dbaa","cabcacaa","","acaabcacab","b","abaaaca","bacaaaaa"] -> 3
["aabaabdbb","bacaabadbbdb","abb","aabaa","ab","bcadbb","adbbcaaadbbb","caaa","bbdbcacadbab","dbbdbdb"] -> 4
["bbcaaabbbabbcadbbacadbbdbdb","b","bbbbaaaaaababa","ca","bb","bdbbacadbbdbbdbbababaacaca","abbaabbabcabaaa","bbbacacacabcacacabaaabb","bbcaaaab","bbbbcaacaadbcaaa","babbabcadbdbacacabbcacab","abcabbbaacadbcadb","bbcabbcadbcacaacaadbadbcaadb","dbbbdbbdbacaabbacabcadbdbacaca","bbaabdbdb","cabcadbbbadbadbbaadbcaca","adbadbadbdbcacadbdbbcaadbcaca","abaabbcab","aaabcaabcaab","bacacabcacaacadbadbb"] -> 6

最初の例では、「am」の後には2つの子を持つノードが必要です。1つは-""-(T)、もう1つは-"s"-(T)です。(リンク先のページの2番目の例の「slow」/「slowly」と比較してください。)ただし、これはルートからリーフへの最長パスの長さに影響しません。
グレッグマーティン

@GregMartin Wikipediaページの実装は少し異なります。これはもっと自然だと思いますが、あなたが言ったように、それは高さに影響を与えません。
Zgarb 16

回答:


2

JavaScript(Firefox 30-57)、137バイト

f=(a,b=["",...a],s=new Set(b.map(w=>w[0])))=>b.length>1?(s.size>1)+Math.max(...(for(c of s)f(a,[for(w of b)if(w&&w[0]==c)w.slice(1)]))):1

空の文字列パラメータを特殊なケースにしないといけないように見えるので、アルゴリズムに問題があるはずです。


私の参照ソリューションでは、空の文字列も特殊なケースです。これは、ルートノードに独自のルールがあるためです。
Zgarb 16

私もそれを特別なケースにする必要があったのですが、その特別なケースは私のソリューションでは1文字だけです(.最初の行の終わり)。
マーティンエンダー

1

網膜69 55バイト

末尾の改行は重要です。

m`.(?<=(?=\D*^\1(?!\2))\D*^(.*)(.))|^.
:$&
T`w
O`
A-2`

入力は改行で区切られたリストです。

最初の行の\A最後の前にaを挿入すると、パフォーマンスを大幅に向上させることができます\D

説明

ノードは、3つの場所で単語に挿入されます。

  • 初め。
  • 最長の接頭辞が別の単語と共有された後。つまり、2つの単語が異なる共有接頭辞です。
  • 終わり。

Retinaでは、数をN+1数えると生成される時間が短くなる傾向があるNため、最後のものは無視します。ただし、入力が空の場合は、開始と終了が同じであるため、開始も無視する必要があります。

実際のカウントを行う:には、ノードがあるすべての場所に挿入します。次に:、単語の最大数を見つけ、そのプラス1を返します。コードは次のように動作します。

m`.(?<=(?=\D*^\1(?!\2))\D*^(.*)(.))|^.
:$&

これにより、すべてのノードが検出されます。キャラクターにマッチします。次に、その文字をグループにキャプチャし2、その前のプレフィックスをグループにキャプチャする後読みに入り1ます。次に、文字列の先頭まで進み、先読みを開始します。これにより、キャプチャされた文字が後に続かない場所で接頭辞を見つけることができるかどうかがチェックされます。この一致が見つかった場合は:、文字の前にaを挿入します。また、現在の単語の最初の文字を照合して、:空でない単語の先頭にaを挿入します。

T`w

これにより、すべての文字が削除され、のみが残ります:

O`

これにより、線が並べ替えられ、最大深度が終了します。

A-2`

これにより、最後の行以外はすべて破棄されます。

そして、最後の空の行は、その行の空の一致の数を数えます。これは、その中のコロンの数より1つ多い数です。

オンラインでお試しください!(最初の行は、改行で区切られたテストスイートを有効にします。各テストケースは、代わりにカンマ区切りを使用します。)

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