Suchen Sie in Java nach Teilsträngen, die Palindrome sind

1. Übersicht

In diesem kurzen Tutorial werden wir verschiedene Ansätze durchlaufen, um alle Teilzeichenfolgen innerhalb einer bestimmten Zeichenfolge zu finden, die Palindrome sind . Wir werden auch die zeitliche Komplexität jedes Ansatzes bemerken.

2. Brute-Force-Ansatz

Bei diesem Ansatz durchlaufen wir einfach die Eingabezeichenfolge, um alle Teilzeichenfolgen zu finden. Gleichzeitig prüfen wir, ob der Teilstring ein Palindrom ist oder nicht:

public Set findAllPalindromesUsingBruteForceApproach(String input) { Set palindromes = new HashSet(); for (int i = 0; i < input.length(); i++) { for (int j = i + 1; j <= input.length(); j++) { if (isPalindrome(input.substring(i, j))) { palindromes.add(input.substring(i, j)); } } } return palindromes; }

Im obigen Beispiel vergleichen wir den Teilstring einfach mit seiner Rückseite, um festzustellen, ob es sich um ein Palindrom handelt:

private boolean isPalindrome(String input) { StringBuilder plain = new StringBuilder(input); StringBuilder reverse = plain.reverse(); return (reverse.toString()).equals(input); }

Natürlich können wir leicht aus mehreren anderen Ansätzen wählen.

Die zeitliche Komplexität dieses Ansatzes beträgt O (n ^ 3). Während dies für kleine Eingabezeichenfolgen akzeptabel sein kann, benötigen wir einen effizienteren Ansatz, wenn wir in großen Textmengen nach Palindromen suchen.

3. Zentralisierungsansatz

Die Idee beim Zentralisierungsansatz besteht darin , jedes Zeichen als Drehpunkt zu betrachten und in beide Richtungen zu erweitern, um Palindrome zu finden .

Wir werden nur erweitern, wenn die Zeichen auf der linken und rechten Seite übereinstimmen, wodurch die Zeichenfolge als Palindrom qualifiziert wird. Ansonsten fahren wir mit dem nächsten Zeichen fort.

Sehen wir uns eine kurze Demonstration an, in der wir jeden Charakter als Zentrum eines Palindroms betrachten:

public Set findAllPalindromesUsingCenter(String input) { Set palindromes = new HashSet(); for (int i = 0; i < input.length(); i++) { palindromes.addAll(findPalindromes(input, i, i + 1)); palindromes.addAll(findPalindromes(input, i, i)); } return palindromes; }

Innerhalb der obigen Schleife erweitern wir in beide Richtungen, um die Menge aller Palindrome zu erhalten, die an jeder Position zentriert sind. Wir finden Palindrome mit gerader und ungerader Länge, indem wir die Methode findPalindromes zweimal in der Schleife aufrufen :

private Set findPalindromes(String input, int low, int high) { Set result = new HashSet(); while (low >= 0 && high < input.length() && input.charAt(low) == input.charAt(high)) { result.add(input.substring(low, high + 1)); low--; high++; } return result; }

Die zeitliche Komplexität dieses Ansatzes beträgt O (n ^ 2). Dies ist eine Verbesserung gegenüber unserem Brute-Force-Ansatz, aber wir können es noch besser machen, wie wir im nächsten Abschnitt sehen werden.

4. Manachers Algorithmus

Manachers Algorithmus findet den längsten palindromischen Teilstring in linearer Zeit . Wir werden diesen Algorithmus verwenden, um alle Teilzeichenfolgen zu finden, die Palindrome sind.

Bevor wir uns mit dem Algorithmus befassen, werden wir einige Variablen initialisieren.

Zuerst schützen wir die Eingabezeichenfolge am Anfang und am Ende mit einem Begrenzungszeichen, bevor wir die resultierende Zeichenfolge in ein Zeichenarray konvertieren:

String formattedInput = "@" + input + "#"; char inputCharArr[] = formattedInput.toCharArray();

Dann verwenden wir einen zweidimensionalen Array- Radius mit zwei Zeilen - eine zum Speichern der Länge von Palindromen ungerader Länge und die andere zum Speichern der Länge von Palindromen gerader Länge:

int radius[][] = new int[2][input.length() + 1];

Als nächstes iterieren wir über das Eingabearray, um die Länge des Palindroms zu ermitteln, das an Position i zentriert ist, und speichern diese Länge im Radius [] [] :

Set palindromes = new HashSet(); int max; for (int j = 0; j <= 1; j++) { radius[j][0] = max = 0; int i = 1; while (i <= input.length()) { palindromes.add(Character.toString(inputCharArr[i])); while (inputCharArr[i - max - 1] == inputCharArr[i + j + max]) max++; radius[j][i] = max; int k = 1; while ((radius[j][i - k] != max - k) && (k < max)) { radius[j][i + k] = Math.min(radius[j][i - k], max - k); k++; } max = Math.max(max - k, 0); i += k; } }

Schließlich durchlaufen wir den Array- Radius [] [] , um die palindromischen Teilzeichenfolgen zu berechnen, die an jeder Position zentriert sind:

for (int i = 1; i <= input.length(); i++) { for (int j = 0; j  0; max--) { palindromes.add(input.substring(i - max - 1, max + j + i - 1)); } } }

Die zeitliche Komplexität dieses Ansatzes beträgt O (n).

5. Schlussfolgerung

In diesem kurzen Artikel haben wir die zeitliche Komplexität verschiedener Ansätze zum Auffinden von Teilzeichenfolgen diskutiert, die Palindrome sind.

Wie immer ist der vollständige Quellcode der Beispiele auf GitHub verfügbar.