Code Capriccio – String – Wiederholter Teilstring

Wiederholter Teilstring

Dieser Abschnitt entspricht Code Random Notes: Code Random Notes , Erklärungsvideo: Es ist ein bisschen schwierig, mit solchen Saiten zu spielen! | LeetCode: 459. Wiederholte substring_bilibili_bilibili

Übung

Fragelink: 459. Wiederholter Teilstring-LeetCode

Überprüfen Sie anhand einer nicht leeren Zeichenfolge s, ob sie durch mehrmaliges Wiederholen einer ihrer Teilzeichenfolgen erstellt werden kann.

示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

Brute-Force-Lösung

Eine intuitivere Lösung besteht darin, alle möglichen Teilzeichenfolgen zu konstruieren und dann kontinuierlich die verbleibenden Zeichenfolgen abzugleichen, um zu sehen, ob sie durch Wiederholen der aktuellen Teilzeichenfolge gebildet werden können.

Die Länge der Zeichenfolge darf höchstens die Hälfte der Länge der Zeichenfolge betragen, und die Bedingung darf nur erfüllt sein, wenn die Länge der Zeichenfolge ein Vielfaches der Länge der Teilzeichenfolge ist.

Nach dem Erstellen der Teilzeichenfolge besteht meine Lösung darin, substrdie verbleibenden Zeichen der Teilzeichenfolgenlänge kontinuierlich abzufangen, um festzustellen, ob sie der Teilzeichenfolge entsprechen. Allerdings ist die Beurteilungseffizienz der offiziellen Problemlösungen von LeetCode höher. Verwenden Sie insbesondere den i-Zeiger, um die Zeichenfolge s zu durchlaufen und kontinuierlich Teilzeichenfolgen neuer Länge zu erhalten. Verwenden Sie dann den Zeiger j, um ausgehend vom i-Zeiger rückwärts zu laufen und den Vergleich fortzusetzen s[j] 和 s[j - i]. Dieser Satz bedeutet, zu vergleichen, ob das aktuelle Zeichen und das Zeichen an der entsprechenden Position im vorherigen Zyklus gleich sind. Zum Beispiel die Zeichenfolge abc abc, das heißt, wenn die Teilzeichenfolge i = 3 abc ist, vergleichen Sie s[3] und s[0], s[4] und s[1], s[5] und s[2]. . Das heißt, vergleichen Sie ständig, ob jedes Element des aktuellen Zyklus jedem Element des vorherigen Zyklus gleich ist. Dies erspart den Aufbau des Strings in den verbleibenden Zyklen.

class Solution {
    
    
   public:
    bool repeatedSubstringPattern(string s) {
    
    
        int n = s.size();
        for (int i = 1; i  <= n/2; ++i) {
    
    
            // 只有子串能被s整除才可能满足条件
            if (n % i == 0) {
    
    
                bool match = true;
                // abc abc abc
                for (int j = i; j < n; ++j) {
    
    
                    // 不断比较当前字符和上个周期的对应位置的字符是否相等
                    if (s[j] != s[j - i]) {
    
    
                        match = false;
                        break;
                    }
                }
                if (match) {
    
    
                    return true;
                }
            }
        }
        return false;
    }
};
  • Zeitkomplexität: O( n 2 n^2N2 ). Es gibt zwei verschachtelte for-Schleifen. Die äußerste Schleife iteriert von 1 bis n/2, während die innere Schleife die Länge n der angegebenen Zeichenfolge durchläuft. Daher beträgt die Gesamtzeitkomplexität O(n 2 n^2N2
  • Raumkomplexität: O( 1 11 ). Es wird kein zusätzlicher Speicherplatz beansprucht. Es führt lediglich Operationen auf konstantem Niveau für die ursprünglichen Zeichenfolgen aus. Daher ist die Raumkomplexität O(1)

String-Matching

Eine Zeichenfolge, die aus wiederholten Teilzeichenfolgen bestehen kann, z. B. abc abc, kann aus abc bestehen. Das heißt, die erste Hälfte und die zweite Hälfte der Zeichenfolge s sind gleich, beide sind abc. Dann verketten wir die beiden Strings, um abc zu erhaltenabc | ABCabc, sodass die zweite Hälfte des ersten s und die erste Hälfte des zweiten s ein s bilden können. Dann beginnen wir mit der Suche nach s ab der Position des ersten Zeichens. Wenn die Startposition des gefundenen s nicht die Startposition des zweiten s ist, bedeutet dies, dass zwischen den beiden s ein s gebildet werden kann. d.h. v. Chrabc | ABCabc Finden Sie abc. Die Startposition von abc befindet sich nicht an der Startposition des zweiten s, was darauf hinweist, dass es aus wiederholten Teilzeichenfolgen bestehen kann.

Beachten Sie, dass wir hier nur beweisen, dass eine Zeichenfolge, die aus wiederholten Teilzeichenfolgen bestehen kann, solche Eigenschaften hat. Wir beweisen jedoch nicht, dass eine Zeichenfolge mit solchen Eigenschaften definitiv aus wiederholten Teilzeichenfolgen bestehen kann. Zum Beweis dieses Punktes können Sie zu LeetCode gehen Offizielle Lösungsmethode drei. Teil „Korrektheitsnachweis“.

class Solution {
    
    
public:
    bool repeatedSubstringPattern(string s) {
    
    
        return (s + s).find(s, 1) != s.size();
    }
};
  • Zeitkomplexität: O( m + n m+nM+N ). Die Suchfunktion verwendet normalerweise den KMP-Algorithmus und in den meisten Fällen beträgt ihre Zeitkomplexität O(n), wobei n die Länge der Suchzeichenfolge ist. Im schlimmsten Fall, wenn die Musterzeichenfolge mit einem bestimmten Präfix in der Suchzeichenfolge übereinstimmt, beträgt die zeitliche Komplexität des Algorithmus O(m+n), wobei m die Länge der Musterzeichenfolge ist. Dies geschieht normalerweise, wenn die Suchzeichenfolge lang und die Musterzeichenfolge kurz ist und aus denselben Zeichen besteht
  • Raumkomplexität: O( nnN ). Erstellt ein neues String-Objekt, dessen Länge der doppelten Länge des angegebenen Strings entspricht

kmp-Lösung

Die beste Lösung für diese Frage ist die Verwendung von kmp. Wir wissen, dass das nächste Array von kmp die Länge gemeinsamer Suffixe speichert. Beispielsweise sind das längste gleiche Präfix und das längste gleiche Suffix von Abababab Ababab, und der Unterschied zwischen den beiden ist die minimale wiederholte Teilzeichenfolge.

Geben Sie einen einfachen Beweis: Wie in der folgenden Abbildung gezeigt, gilt: Da Präfix und Suffix gleich sind, gilt 1 = 2 und 2 = 3, also 1 = 3. Ebenso gilt: 3=4 und 4=5, also 3=5. Zusammenfassend bedeutet 1=3=5, dass die Zeichenfolge aus Wiederholungen bestehen kann.

Fügen Sie hier eine Bildbeschreibung ein

Basierend auf der obigen Ableitung finden wir das nächste Array. Der letzte Wert des nächsten Arrays ist die Länge des längsten gleichen Suffixes. Die Länge der Zeichenfolge wird von dieser Länge abgezogen, um die Differenz zu erhalten. Wenn die Länge der Zeichenfolge beträgt ein Vielfaches dieser Differenz, gibt „true“ zurück. Wenn das letzte Element des nächsten Arrays 0 ist, d. h. es kein längstes gleiches Präfix oder Suffix gibt oder die Differenz nicht teilbar ist, wird „false“ zurückgegeben.

// 3种情况
abcabd // next[5]=0,返回false
abcab  // next[4]=2,5-2=3无法被5整除,返回false
abcabc // next[5]=3,6-3=3能被整除,返回true

Der Code lautet wie folgt und ähnelt der Lösung der vorherigen Frage kmp. Er bestimmt lediglich die oben genannten drei Situationen, nachdem das nächste Array abgerufen wurde.

class Solution {
    
    
public:
    void getNext (int* next, const string& s){
    
    
        next[0] = 0;
        int j = 0;
        for(int i = 1;i < s.size(); i++){
    
    
            while(j > 0 && s[i] != s[j]) {
    
    
                j = next[j - 1];
            }
            if(s[i] == s[j]) {
    
    
                j++;
            }
            next[i] = j;
        }
    }
    bool repeatedSubstringPattern (string s) {
    
    
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        // 关键语句,对应上面所讲的3种情况
        if (next[len - 1] != 0 && len % (len - (next[len - 1] )) == 0) {
    
    
            return true;
        }
        return false;
    }
};
  • Zeitkomplexität: O( nnN ). Die Zeitkomplexität der getNext-Funktion beträgt O(n). Die Zeitkomplexität der RepeatedSubstringPattern-Funktion stammt hauptsächlich von der getNext-Funktion, sodass die gesamte Zeitkomplexität O(n) beträgt.
  • Raumkomplexität: O( nnN ). Ein Array der Größe n wird verwendet, um die maximale Länge der Präfix- und Suffixübereinstimmung zu speichern, sodass die Raumkomplexität O(n) beträgt.

Guess you like

Origin blog.csdn.net/zss192/article/details/129973633
Recommended