Letter Combinations of a Phone Number
Auf einer Telefontastatur sind jeder Ziffer von 2 bis 9 einige Buchstaben zugeordnet: 2 ist abc, 3 ist def, 4 ist ghi, 5 ist jkl, 6 ist mno, 7 ist pqrs, 8 ist tuv und 9 ist wxyz.
Du erhältst eine Zeichenfolge digits. Wähle für jede Ziffer einen Buchstaben aus, wobei die Reihenfolge der Ziffern erhalten bleibt, und du erhältst eine Zeichenfolge, die mit den Tasten eingegeben werden kann. Gib alle solchen Zeichenfolgen in lexikografischer (Wörterbuch-)Reihenfolge zurück.
Funktion
- digitsstring
- die gedrückten Ziffern, jeweils von 2 bis 9
- Gibt zurückstring-array
- jede Zeichenfolge, die mit den Tasten eingegeben werden kann, in lexikografischer Reihenfolge
Einschränkungen
1 ≤ digits.length ≤ 4- Jedes Zeichen von
digitsist eine Ziffer von2bis9. - Die Antwort enthält höchstens
44 = 256Zeichenfolgen.
Beispiele
- Eingabe
- digits = "23"
- Ausgabe
- ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
- Erklärung
- 2 bietet
a,b,cund 3 bietetd,e,f. Jeder erste Buchstabe wird mit jedem zweiten Buchstaben kombiniert: 3 × 3 = 9 Zeichenfolgen, sortiert, wobei sich der erste Buchstabe am langsamsten ändert.
- Eingabe
- digits = "7"
- Ausgabe
- ["p", "q", "r", "s"]
- Erklärung
- Bei einer einzelnen Ziffer ist jeder ihrer Buchstaben eine vollständige Antwort. 7 ist eine der beiden Tasten mit vier Buchstaben, daher hat die Antwort vier Zeichenfolgen.
- Eingabe
- digits = "94"
- Ausgabe
- ["wg", "wh", "wi", "xg", "xh", "xi", "yg", "yh", "yi", "zg", "zh", "zi"]
- Erklärung
- 9 hat vier Buchstaben und 4 hat drei, also gibt es 4 × 3 = 12 Zeichenfolgen. Alle drei Zeichenfolgen, die mit
wbeginnen, kommen vor der ersten, die mitxbeginnt.
Weiterführende Frage
Angenommen, du möchtest nur die Kombinationen, die echte Wörter aus einem Wörterbuch sind. Wie könntest du vermeiden, zuerst alle 4^n Zeichenfolgen zu erstellen?
Tipps
Öffne sie nacheinander. Jeder verrät ein bisschen mehr.
Stelle die Auswahlmöglichkeiten als Baum dar. Die erste Ebene wählt einen Buchstaben für die erste Ziffer aus, die zweite Ebene einen Buchstaben für die zweite Ziffer und so weiter. Was ergibt der Pfad von der Wurzel zu einem Blatt?
Jedes Blatt ist eine Antwort, und jede Antwort ist ein Blatt. Durchlaufe den Baum tiefensuchend, probiere die Buchstaben jeder Taste von links nach rechts aus, und du triffst die Blätter in Wörterbuchreihenfolge an.
Behalte einen wachsenden String bei. Hänge an Position
inacheinander jeden Buchstaben vondigits[i]an, gehe weiter zu Positioni+1und entferne dann den Buchstaben wieder. Wennidas Ende vondigitserreicht, speichere eine Kopie des Strings.
Lösung
Die Antwort enthält bis zu 4^n Zeichenfolgen, daher erfordert jede Lösung mindestens so viel Aufwand, um sie auszugeben. Entscheidend ist, jede Auswahl genau einmal zu erzeugen, ohne eine auszulassen oder zu wiederholen. Das ist Backtracking über einen Entscheidungsbaum mit einer Ebene pro Ziffer, wobei jedes Blatt eine Antwort ist.
Baue die Zeichenfolgen Ziffer für Ziffer auf
Idee
Beginne mit einer Liste, die eine leere Zeichenfolge enthält, und erweitere sie Ziffer für Ziffer. Für "23" wird daraus durch die Ziffer 2 a, b, c, und die 3 erweitert jede davon um d, e und f, sodass neun Zeichenfolgen entstehen.
Die Reihenfolge bleibt sortiert. Wenn die Liste vor einer Ziffer sortiert ist, erweiterst du die Präfixe in dieser Reihenfolge und jedes Präfix um die Buchstaben seiner Taste von links nach rechts: Ein früheres Präfix kommt weiterhin zuerst, und gleiche Präfixe werden nach dem neuen Buchstaben geordnet.
Der Aufwand entspricht der Größe der Antwort, aber während du eine Ebene aufbaust, bleibt auch die gesamte vorherige Ebene im Speicher.
Algorithmus
- Beginne mit
combos = [""], einem leeren Präfix. - Erstelle für jede Ziffer eine neue Liste: Füge für jedes Präfix in
combosund jeden Buchstaben auf der Taste dieser Zifferprefix + letterhinzu. - Ersetze
combosdurch die neue Liste. - Gib nach der letzten Ziffer
comboszurück.
KEYPAD = {"2": "abc", "3": "def", "4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"}
def letterCombinations(digits):
combos = [""] # every prefix built so far; one empty prefix to start
for digit in digits:
# Each old prefix grows by each letter of this digit, in order.
combos = [prefix + letter for prefix in combos for letter in KEYPAD[digit]]
return combosBacktracking über den Entscheidungsbaum
Idee
Die Antworten sind die Blätter eines Entscheidungsbaums. Die Wurzel ist die leere Zeichenfolge, und jede Ebene fügt einen Buchstaben der nächsten Ziffer hinzu: Für "23" hat die Wurzel die Kinder a, b, c, jedes davon mit Kindern für d, e, f.
Durchlaufe ihn tiefensuchend mit einem Puffer, path. Auf Ebene i wählst du einen Buchstaben von digits[i], indem du ihn anhängst, erkundest ihn, indem du für i+1 rekursiv aufrufst, und machst die Auswahl rückgängig, indem du den Buchstaben entfernst. Durch das Rückgängigmachen kann ein Puffer für den ganzen Baum verwendet werden: Nach ad, ae und af bringt das Entfernen path zurück zu a, dann zur leeren Zeichenfolge, bereit für b. Wenn i das Ende von digits erreicht, speichere eine Kopie.
Der Zeitaufwand beträgt weiterhin O(4^n · n), aber der zusätzliche Speicherbedarf besteht aus dem Puffer und dem Aufrufstapel, O(n).
Algorithmus
- Behalte einen leeren
pathund ein leeresresult. - Definiere
backtrack(i): Wennider Länge vondigitsentspricht, speichere eine Kopie vonpathund kehre zurück. - Andernfalls füge für jeden Buchstaben auf der Taste von
digits[i]der Reihe nach diesen zupathhinzu, rufebacktrack(i+1)auf und entferne ihn anschließend. - Rufe
backtrack(0)auf und gibresultzurück.
KEYPAD = {"2": "abc", "3": "def", "4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"}
def letterCombinations(digits):
result = []
path = [] # the letters chosen so far, one per digit
def backtrack(i):
if i == len(digits):
# Every digit has a letter: this leaf is one finished string.
result.append("".join(path))
return
for letter in KEYPAD[digits[i]]:
path.append(letter) # choose
backtrack(i + 1) # explore the digits after this one
path.pop() # undo, so the next letter can take its place
backtrack(0)
return result
Stolperfallen und Grenzfälle
- Davon ausgehen, dass jede Taste drei Buchstaben hat. Wenn man drei Buchstaben ab dem Index
(d-2)*3des Alphabets nimmt, fällt dassbei 7 weg und 8 beginnt mits. Schreibe das Tastenfeld als Tabelle auf. - Das Zurücksetzen vergessen.
pathwächst immer weiter, und die zweite Antwort für"23"lautetadestattae. - Den Puffer statt einer Kopie speichern. In Python speichert
result.append(path)neunmal dieselbe Liste, und am Ende ist sie leer. - Die Buchstaben einer Taste von rechts nach links durchgehen oder in der iterativen Version Zeichenfolgen aus einem Stapel aufbauen. Beides zerstört die sortierte Reihenfolge.
- In PHP und R kommt
"23"möglicherweise als Zahl 23 an. Wandle es in Text um, bevor du auf seine Zeichen zugreifst.
Häufige Fragen3
Wie hoch ist die Zeitkomplexität der Buchstabenkombinationen einer Telefonnummer?
O(4^n · n) für n Ziffern: Es kann 4^n Zeichenfolgen geben, wenn jede Ziffer 7 oder 9 ist, und jede benötigt n Schritte zum Schreiben. Das ist die Größe der Ausgabe, daher ist keine Lösung besser. Backtracking benötigt zusätzlich zur Ausgabe O(n) Speicherplatz.
Warum gibt Backtracking die Kombinationen in sortierter Reihenfolge zurück?
Alle Antworten haben dieselbe Länge, und eine Tiefensuche vervollständigt jeden String, der mit a beginnt, bevor sie b auswählt. Das gilt auf jeder Ebene, solange die Buchstaben jedes Schlüssels von links nach rechts ausprobiert werden. Das ist Wörterbuchreihenfolge, daher ist keine Sortierung nötig.
Wie sieht es mit den Ziffern 0 und 1 aus?
Auf einer Telefontastatur sind den Ziffern 0 und 1 keine Buchstaben zugeordnet, und diese Version verwendet nur 2 bis 9. Falls sie vorkommen könnten, müsstest du entscheiden, ob eine solche Ziffer übersprungen wird oder die Antwort leer macht. Frage im Vorstellungsgespräch nach, was gewünscht ist.
Ähnliche Aufgaben
Aufgaben mit denselben Ideen. Wer zwei oder drei davon löst, behält das Muster.
def letterCombinations(digits):
# Schreibe hier den CodeTest #1
Test #2
Test #3
Argument
digits = "23"
Erwartete Ausgabe
["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]