2016-12-30 5 views
-1

Hier ist mein Code für dieses Problem. Ich benutze Trie Baum für diese Lösung und frage mich, ob andere bessere Ideen in Bezug auf bessere Zeit Komplexität oder Komplexität des Raumes. Auch Bugs und Codestil-Ratschläge sind willkommen.Finde die kleinsten Subset-Präfixe

Problem:

eine Menge von Strings gegeben, kehrt die kleinste Teilmenge des gegebenen Eingangswortes gesetzt --- eingestellten Präfixe für alle Eingangsworte im gegebenen Eingangswort enthält. Das Präfix sollte ein vollständiges Eingabewort in dem gegebenen Eingabesatz sein, mit Ausnahme eines Präfixes eines gegebenen Wortes. Für ein Wort, das kein Präfix hat, gibt sich selbst zurück.

Wenn die Liste [ 'foo', 'FOOG', 'Lebensmittel', 'asdf'] return [ 'foo', 'asdf']

Die Rückkehr ist foo seit foo ist Präfix für foo (selbst), Präfix für foog und Präfix für food (mit anderen Worten, foo könnte längere Zeichenfolge wie foog und food "darstellen"). Ausgabe enthält auch asdf, weil es kein Präfix für andere Wörter in der Eingabeliste ist, also selbst ausgegeben.

Der leere Satz ist keine richtige Antwort, da er nicht die längsten möglichen Präfixe enthält.

Quellcode:

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

Ich finde deine Problembeschreibung unklar. Warum nicht einfach den gesamten Eingabesatz zurückgeben - einer davon ist der längste mögliche Präfix für ein gegebenes Wort. –

+2

Das Problem ist schlecht formuliert: Was ist zum Beispiel die erwartete Ausgabe für '[fab, fabc, fbc]'? Ist es '[fab, fbc]' oder nur '[f]'? (Wie häufig sollte das "gemeinsame Präfix" sein? Reicht es aus, nur von zwei Elementen geteilt zu werden oder wenn es von mehr als zwei geteilt wird, dann hat "Gemeinsamkeit" Vorrang vor "Maximallänge"?) –

+0

@RoryDaulton, brauche ich um den kleinsten Satz zurückzugeben, der das Präfix für alle eingegebenen Wörter ist. Ich bearbeite die Frage Beschreibung, bitte zögern Sie zu korrigieren, wenn immer noch nicht klar. Ihr Rat zu ursprünglichen Fragen wird sehr geschätzt. –

Antwort

1

Ich denke, die Frage eindeutig ist. (Vielleicht war es vor den Änderungen härter). Die Antwort ist, dass Trie genau richtig erscheint.

Erstellen Sie einen Trie aus den Eingabewörtern, dann durchlaufen Sie zuerst die Tiefe. Jedes Mal, wenn Sie einen Knoten (einen inneren Knoten oder ein Blatt) finden, der sich im Eingabe-Set befindet, fügen Sie das Wort an diesem Knoten zur Ausgabe hinzu und hören auf, die untergeordneten Elemente zu durchsuchen.

+0

Danke danh, fragen Sie sich, ob ein anderer stringbasierter Algorithmus wie KMP Ihnen hilft, die Zeitkomplexität zu verbessern? –

+1

Das ist eine nette Idee, aber es ist komplex, jedes Wort mit allen anderen zu vergleichen. Ich bin zu rostig, um das zu beweisen, aber deine derzeitige Idee ist O (n * durchschnittliche Wortlänge), wobei n die Wortzahl ist. Mit einem geschickten String-Präfix-Tester, selbst wenn es O (1) gibt, gibt man O (n^2), wo man jedes Wort mit anderen vergleicht, um zu bestimmen, ob es in der Ausgabe stehen kann – danh

+1

"Ich denke, die Frage ist eindeutig . " "Ja wirklich?" Was ist mit '[f, fa, fab]'? Schließlich ist "fa" ein Präfix für "fab", also bitte zitieren Sie ad litteram die Regel in der Spezifikation, die verbietet, dass "fa" als Präfixwort aufgeführt wird. –

1

Ich ziehe den einfacheren while -loop Ansatz mit einer Art am Anfang:

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 

Es ist eine ziemlich effiziente Umsetzung im schlimmsten Fall O läuft in (n ** 2), wenn kein String ist ein Präfix jede andere Zeichenfolge.


Postscript # 1: Sie können die Art etwas effizienter machen, indem nur von der Länge der Wörter Sortierung anstelle von Länge und alphabetisch. B. diese Zeile ändert:

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

zu:

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

natürlich eine Art ist O (n (log n)), welche die untere gebunden ist auf der Laufzeit/Komplexität.


Postscript # 2:

Wenn Sie Speichereigenschaften definiert bevorzugen, können Sie anstelle der Filterung auf der words Liste Markierung verwenden.Eine Markierung Version dieses Algorithmus würde wie folgt aussehen:

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 ] 

etwas ausführlicher als meine bevorzugte Filterversion ist, hat aber den Vorteil, nicht ständig die Schaffung/in jedem aufeinanderfolgenden Durchlauf der Schleife die Worte Array zu zerstören.

+0

Danke 2ps, warum denkst du, dass dein Code Worst Case 'O (n ** 2) 'ist? Ich denke, es ist immer "O (n ** 2)", da Sie jedes Wortpaar vergleichen? Bitte zögern Sie nicht, mich zu korrigieren, wenn ich Ihre Logiken falsch lese. –

+0

Ein weiterer Kommentar ist, dass Sie 'words' verwenden, um die' while' Schleife zu steuern und in der Schleife selbst, ändern Sie den Wert der Schleifenkontrollvariablen 'words', nicht sicher, ob es eine gute Idee ist? Ich komme aus C++/Java und das gemeinsame Verständnis berührt nicht Regelkreis Variable als eine gute Praxis. Vielen Dank. –

+0

@LinMa: Es sieht so aus, als ob Sie die Logik der while-Schleife nicht korrekt befolgt haben. Der Algorithmus vergleicht nicht jedes Wortpaar. Nach dem ersten Durchlauf der while-Schleife wird "foo" mit allen anderen Wörtern verglichen und "foog" und "food" werden aus der Wörterliste herausgefiltert. Auf dem zweiten (und letzten) Durchlauf der 'while'-Schleife wird" asdf' "zur minimalen Menge hinzugefügt, aber nicht mit irgendeinem anderen Wort verglichen. QED. – 2ps

Verwandte Themen