Suche nach Substrings, die Palindrome in Java sind

Finden Sie Substrate, die Palindrome sind, in Java

1. Überblick

In diesem kurzen Tutorial werden wir verschiedene Ansätze fürfinding all substrings within a given string that are palindromes durchgehen. 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 ausseveral other approaches wählen.

The time complexity of this approach is 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 im Zentralisierungsansatz istconsider each character as the pivot and expand in both directions to find palindromes.

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;
}

In der obigen Schleife erweitern wir in beide Richtungen, um die Menge aller Palindrome an jeder Position zu zentrieren. Wir finden Palindrome mit gerader und ungerader Länge, indem wir die MethodefindPalindromes 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;
}

The time complexity of this approach is 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

Manacher’s algorithmfinds the longest palindromic substring in linear time. 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 ein zweidimensionales Arrayradius 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 durchlaufen wir das Eingabearray, um die Länge des Palindroms zu ermitteln, das an Positionzentriert ist. Sand speichert diese Länge inradius[][]:

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 das Arrayradius[][], 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 <= 1; j++) {
        for (max = radius[j][i]; max > 0; max--) {
            palindromes.add(input.substring(i - max - 1, max + j + i - 1));
        }
    }
}

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

5. Fazit

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

Wie immer ist der vollständige Quellcode der Beispieleover on GitHub verfügbar.