2016-12-30 8 views
-1

これは私のこの問題のコードです。私はこのソリューションのためにTrie treeを使用しています。時間の複雑さや空間の複雑さの点で他の優れたアイデアがあるかどうかは疑問です。また、バグやコードスタイルに関するアドバイスも感謝しています。最小サブセットプレフィックスを見つける

問題:文字列の集合が与えられる

、与えられた入力ワードセット内のすべての入力単語の接頭辞が含まれて設定された所定の入力ワードの最小サブセットを---返します。プレフィックスは、指定された入力セット内の完全な入力単語でなければなりません。プレフィックスを持たない単語の場合は、 がそれ自身を返します。

リストがある場合は[ 'FOO'、 'foog'、 '食べ物'、 '空自']リターン[ 'FOO'、 '空自']

リターンはfoo以来fooあるの接頭辞でありますfoo(それ自体)、foogの接頭辞、foodの接頭辞(つまり、fooは、foogfoodのような長い文字列を表すことができます)。入力リストの他の単語の接頭辞ではないため、出力にはasdfも含まれているため、出力自体が出力されます。

空のセットは、可能な限り長いプレフィックスが含まれていないため、正解ではありません。

ソースコード:

from collections import defaultdict 
class TrieNode: 
    def __init__(self): 
     self.children = defaultdict(TrieNode) 
     self.isEnd = False 
    def insert(self, word): 
     node = self 
     for w in word: 
      node = node.children[w] 
     node.isEnd = True 
    def find_prefix(self, prefix, result): 
     if self.isEnd: 
      result.append(prefix[:]) 
      return 
     for k,v in self.children.items(): 
      prefix.append(k) 
      v.find_prefix(prefix, result) 
      prefix.pop(-1) 

if __name__ == "__main__": 
    words = ['foo', 'foog', 'food', 'asdf'] 
    root = TrieNode() 
    for w in words: 
     root.insert(w) 
    result = [] 
    root.find_prefix([], result) 
    print result 
+2

問題の説明が不明です。なぜ入力集合全体を返すのではなく、それらのうちの1つは、与えられた単語の可能な最長接頭辞です。 –

+2

問題は不適切です。例えば、 '[fab、fabc、fbc]'の期待される出力は?それは '[fab、fbc]'または単に '[f]'ですか? (共通の接頭辞はどのように '共通の接頭辞'でなければならないのですか?2つの要素で共有するだけで十分ですか?2つ以上共有する場合は '共通性'が「最大長」よりも優先されますか) –

+0

@RoryDaulton、すべての入力単語の接頭辞である最小の集合を返す。質問の説明も編集しますが、まだ明確でない場合は、修正してください。元の質問に対するあなたのアドバイスは高く評価されます。 –

答えて

1

私は質問があいまいだと思います。 (たぶんそれは編集の前に厳しいものでした)。答えは、トライが正確に正しいと思われることです。

入力語からトライを作成してから、最初にトラバースします。入力セット内にあるノード(内部ノードまたはリーフ)を見つけるたびに、そのノードの単語を出力に追加し、その子の検索をやめます。

+0

KMPのような他の文字列ベースのアルゴリズムが時間の複雑さを改善するのに役立つかどうか疑問に思うdanhさん、ありがとうございますか? –

+1

それは良い考えですが、各単語を他のすべての単語と比較するのは複雑です。私は証明するにはあまりにも錆びますが、あなたの現在のアイデアはO(n *平均単語長)です(nは単語数です)。巧妙な文字列接頭辞テスターを使用すると、たとえそれがO(n^2)であっても、各単語を他の単語と比較して、出力にそれらがあるかどうかを判断することができます。 – danh

+1

"質問はあいまいではないと思います"本当に? '[f、fa、fab]'はどうですか?結局のところ、 'fa'は' fab'のプレフィックスですから、 'fa'をプレフィックスワードとしてリストされていることを禁じている仕様の規則を広告litteramに引用してください。 –

1

私が先頭にソートして単純while -loopアプローチを好む:

minimal = [] 
words = ['foo', 'foog', 'food', 'asdf'] 
words.sort(key=lambda x: (len(x), x)) 
while words: 
    word = words[0] 
    minimal.append(word) 
    words = [ x for x in words[1:] if not x.startswith(word) ] 
print minimal 

それは最悪Oでで実行されている非常に効率的な実装である(N ** 2)は、文字列は接頭辞のないとき他の文字列。


ポストスクリプト#1:あなたは少しより効率的なだけの代わりに、両方の長さの単語の長さにソートすることにより、およびアルファベット順に並べ替えを行うことができます。例えば、この行を変更:

words.sort(key=lambda x: (len(x), x)) 

に:もちろん

words.sort(key=lambda x: len(x)) 

ソートすることであるO(N(ログn))走行時間/複雑さの下限です。


ポストスクリプト#2:

あなたが定義したメモリ特性を好む場合は、マーキングの代わりwordsリストにフィルタリングを使用することができます。このアルゴリズムのマーキングバージョンは、次のようになります。それは少し冗長な私の好みのフィルタリングバージョンよりもですが、継続的に作成/ループの各連続パス内の単語の配列を破壊しないという利点があり

words = [ 'foo', 'foog', 'food', 'asdf' ] 
    words.sort(key=lambda x: len(x)) 
    marked = [ False for _ in words ] 
    for i in range(0, len(words)): 
     is_marked = marked[i] 
     if is_marked: continue 
     word = words[i] 

     for j in range(i + 1, len(words)): 
      if not marked[j] and words[j].startswith(word): 
       marked[j] = True 
    minimal = [ word for word, is_marked in zip(words, marked) if not is_marked ] 

+0

ありがとう2ps、なぜあなたのコードが最悪の場合 'O(n ** 2)'だと思いますか?私はあなたが各単語のペアを比較するので、常に 'O(n ** 2)'であると思いますか?あなたのロジックを読んで間違っている場合は、私を修正してください。 –

+0

また、別のコメントは、 'while'ループを制御するために' words'を使用しています。ループ制御変数 'words'の値を変更すると良いでしょうか?私はC++/Javaから来ていて、一般的な理解は良い制御としてループ制御変数には触れていません。ありがとう。 –

+0

@LinMa:あなたは 'while'ループのロジックに正しく従わなかったようです。アルゴリズムは各単語のペアを比較しません。 whileループの最初のパスの後、 '' foo''は他のすべての単語と比較され、 '' foog''と '' food''は単語リストから除外されます。したがって、 'while'ループの2回目(そして最後の)パスでは、' 'asdf''が最小セットに追加されますが、他の単語と比較されることはありません。 QED。 – 2ps

関連する問題