Übereinstimmung des Auftretens und des Musters von Zeichen von String2 in String1

8

Ich wurde diese Frage in einem Telefoninterview für ein Sommerpraktikum gestellt und versuchte, eine n * m-Komplexitätslösung (obwohl sie nicht genau war) in Java zu finden.

Ich habe eine Funktion, die 2 Zeichenfolgen akzeptiert, angenommen "common" und "cmn". Es sollte True zurückgeben, basierend auf der Tatsache, dass "c", "m", "n" in der gleichen Reihenfolge in "common" vorkommen. Wenn die Argumente jedoch "common" und "omn" wären, würde sie False zurückgeben, obwohl sie in der gleichen Reihenfolge auftreten, aber 'm' auch nach 'o' erscheint (was die Musterübereinstimmungsbedingung nicht erfüllt)

Ich habe mit Hashmaps und Ascii Arrays darüber gearbeitet, aber noch keine überzeugende Lösung gefunden! Von dem, was ich bis jetzt gelesen habe, kann es mit Boyer-Moore- oder Levenshtein-Distanzalgorithmen verwandt werden?

Hoffe auf Atempause bei stackoverflow! :)

Bearbeiten : In einigen Antworten wird die Wortlänge reduziert oder ein Hashset erstellt. Aber nach meinem Verständnis kann diese Frage nicht mit Hash-Sets gemacht werden, weil das Auftreten / Wiederholen jedes Zeichens in der ersten Zeichenkette seine eigene Bedeutung hat. PASS-Bedingungen - "con", "cmn", "cm", "cn", "mn", "auf", "co". FAIL-Bedingungen, die anders aussehen könnten - "com", "omn", "mon", "om". Diese sind FALSE / FAIL, weil "o" sowohl vor als auch nach "m" auftritt. Ein anderes Beispiel - "google", "ole" würde PASS, aber "google", "gol" würde fehlschlagen, weil "o" auch vor "g" erscheint!

    
MadTest 03.05.2011, 02:34
quelle

8 Antworten

4

Ich denke, es ist ziemlich einfach. Führen Sie das Muster durch, und für jedes Zeichen wird der Index des letzten Vorkommens in der Zeichenfolge abgerufen. Der Index muss immer größer werden, andernfalls wird false zurückgegeben. Also im Pseudocode:

%Vor%

Bearbeiten: Sie könnten den Code weiter verbessern, indem Sie index als Startindex an die Methode lastIndexOf übergeben. Dann müssten Sie checkindex nicht mit index vergleichen und der Algorithmus wäre schneller.

Aktualisiert: Ein Fehler im Algorithmus wurde behoben. Zusätzliche Bedingung hinzugefügt, um die Reihenfolge der Buchstaben im Muster zu berücksichtigen.

    
raymi 03.05.2011, 15:50
quelle
2

Eine ausgezeichnete Frage und ein paar Stunden Recherche und ich denke, ich habe die Lösung gefunden. Lassen Sie mich zuerst versuchen, die Frage in einem anderen Ansatz zu erklären.

Voraussetzung:

Betrachten wir dasselbe Beispiel 'common' (mainString) und 'cmn' (subString). Zunächst müssen wir uns darüber im Klaren sein, dass sich alle Zeichen innerhalb des mainString und auch des subString wiederholen können und da das Muster, auf das wir uns konzentrieren, eine große Rolle spielt. Also müssen wir wissen:

  • Index des Charakters (am wenigsten und am höchsten)

Lasst uns das in der Warteschleife halten und weitermachen und die Muster noch ein wenig überprüfen. Für das Wort common müssen wir herausfinden, ob das bestimmte Muster cmn vorhanden ist oder nicht. Die verschiedenen möglichen Muster sind: - (Vorrang gilt)

  • c - & gt; o
  • c - & gt; m
  • c - & gt; n
  • o - & gt; m
  • o - & gt; o
  • o - & gt; n
  • m - & gt; m
  • m - & gt; o
  • m - & gt; n
  • o - & gt; n

Zu jedem Zeitpunkt muss dieser Vorrang und Vergleich gültig sein. Da der Vorrang eine große Rolle spielt, müssen wir den Index jedes einzelnen Zeichens haben, anstatt die verschiedenen Muster zu speichern.

Lösung

Der erste Teil der Lösung besteht darin, eine Hash-Tabelle mit den folgenden Kriterien zu erstellen: -

  1. Erstellen Sie eine Hash-Tabelle mit dem Schlüssel als jedes Zeichen der mainString
  2. Jeder Eintrag für einen eindeutigen Schlüssel in der Hash-Tabelle speichert zwei Indizes, d. h. lowIndex und higherIndex
  3. Durchlaufen Sie den mainString und aktualisieren Sie für jedes neue Zeichen einen neuen Eintrag von lowIndex in den Hash mit dem aktuellen Index des Zeichens in mainString.
  4. Wenn Kollision auftritt, aktualisieren Sie den aktuellen Index mit dem Eintrag highlyIndex, und zwar bis zum Ende von String

Zweiter und Hauptteil des Mustervergleichs: -

  1. Setze Flag als falsch
  2. Schleife durch die Unterzeichenfolge und für jedes Zeichen als Schlüssel, retreive die Details aus dem Hash.
  3. Machen Sie dasselbe für den nächsten Charakter.
  4. Überprüfen Sie vor dem Schleifeninkrement zwei Bedingungen

    %Vor%
  5. Zeigen Sie die Flagge an

NB: Da ich in Java nicht so vielseitig bin, habe ich den Code nicht eingereicht. Aber jemand kann versuchen, meine Idee zu implementieren

    
NirmalGeo 03.05.2011 09:37
quelle
1

Ich habe diese Frage in ineffizienter Weise selbst gemacht, aber es gibt ein genaues Ergebnis! Ich würde mich freuen, wenn jemand daraus einen effizienten Code / Algorithmus ausmachen kann!

Erstellen Sie eine Funktion "Check", die 2 Strings als Argumente akzeptiert. Überprüfen Sie jedes Zeichen von String 2 in String 1. Die Reihenfolge des Auftretens jedes Zeichens von s2 sollte in S1 als wahr bestätigt werden.

  1. Nimm Zeichen 0 aus der Zeichenkette p und traversiere durch die Zeichenkette s, um den Index des ersten Vorkommens zu finden.
  2. Durchqueren Sie das gefüllte ascii-Array, um einen Wert zu finden, der größer ist als der Index des ersten Auftretens.
  3. Durchqueren Sie weiter, um das letzte Vorkommen zu finden, und aktualisieren Sie das ASCII-Array
  4. Nimm Zeichen 1 aus der Zeichenkette p und traversiere durch die Zeichenkette s, um den Index des ersten Vorkommens in der Zeichenkette s
  5. zu finden
  6. Durchqueren Sie das gefüllte ascii-Array, um einen Wert zu finden, der größer ist als der Index des ersten Auftretens. Falls gefunden, gebe False zurück.
  7. Durchqueren Sie weiter, um das letzte Vorkommen zu finden, und aktualisieren Sie das ASCII-Array

Wie man beobachten kann, ist dies eine Bruteforce-Methode ... Ich denke, O (N ^ 3)

%Vor%     
MadTest 03.05.2011 15:38
quelle
0

Ist es in O (n log n) nicht möglich?

Schritt 1: Verringern Sie die Zeichenfolge, indem Sie alle rechts angezeigten Zeichen entfernen. Genau genommen müssen Sie nur Zeichen löschen, wenn sie in der Zeichenkette erscheinen, die Sie überprüfen.

%Vor%

Schritt 2, überprüfen Sie die Eindämmung.

%Vor%

Und um Ihre zweite Frage zu beantworten, nein, Levenshtein Abstand wird Ihnen nicht helfen, da es die Eigenschaft hat, dass, wenn Sie die Argumente austauschen, die Ausgabe die gleiche ist, aber der Algo nicht will.

    
Mike Samuel 03.05.2011 02:55
quelle
0
%Vor%

Ausgabe:

%Vor%     
Emil 03.05.2011 05:51
quelle
0

Ich würde dies als einen der schlimmsten Codeabschnitte, die ich je geschrieben habe, oder als eines der schlechtesten Codebeispiele im Stackoverflow betrachten ... aber rate mal ... alle deine Bedingungen sind erfüllt!
Kein Algorithmus konnte wirklich zu dem Bedarf passen, also habe ich nur Bruteforce benutzt ... probiere es aus ...
Und ich könnte mich nur weniger für die Komplexität von Raum und Zeit interessieren ... mein Ziel war es zuerst zu versuchen und es zu lösen ... und es vielleicht später zu verbessern!

%Vor%

-IvarD

    
topgun_ivard 03.05.2011 09:39
quelle
0

Ich denke, dies ist kein Test Ihrer Informatikgrundlagen, sondern mehr, was Sie praktisch in der Java-Programmierumgebung tun würden.

Sie könnten einen regulären Ausdruck aus dem zweiten Argument konstruieren, d. h.

%Vor%

... und testen Sie dann die Kandidaten-Zeichenfolge, indem Sie entweder String.matches (...) oder mit Muster Klasse.

In generischer Form sollte die Konstruktion der RegExp in den folgenden Zeilen sein.

  

exp - & gt; in [0] . * + für jedes x: 2 - & gt; in.Länge {( in [x-1] +    [^ in [x-2]] * + in [x] )}

zum Beispiel:

  

demmn - & gt; d. * e [^ d] * m [^ e] * m [^ m] * n

    
Adrian Regan 04.05.2011 14:28
quelle
0

Ich habe es selbst auf eine andere Art und Weise versucht. Teilen Sie einfach meine Lösung.

Öffentliche Klasse PatternMatch {

%Vor%

}

    
FourOfAKind 16.05.2011 06:49
quelle

Tags und Links