Ich mag kein Wechselgeld!

19

Eingang:

Zwei Zeichenfolgen ohne Zeilenumbrüche oder Leerzeichen.

Ausgabe:

Beide Eingabezeichenfolgen in getrennten Zeilen, ggf. mit Leerzeichen für eine der beiden Zeichenfolgen. Und eine dritte Zeile mit den Zeichen A, R, Mund , was hinzugefügt , entfernt , verändert und unverändert .

Wir fügen der oberen oder unteren Eingabezeichenfolge Leerzeichen hinzu (falls erforderlich). Ziel dieser Herausforderung ist es, möglichst wenig Änderungen ( ARM) auszugeben , auch bekannt als Levenshtein-Abstand .

Beispiel:

Angenommen, die Eingabezeichenfolgen sind ABCDEFund AFBECD, dann wäre die Ausgabe wie folgt:

A B CDEF
AFBECD  
 A A  RR

Hier sind einige andere mögliche ungültige Ausgaben als Beispiel (und es gibt noch viel mehr):

ABCDEF
AFBECD
 MMMMM

A BCDEF
AFBECD 
 A MMMR

AB CDEF
AFBECD 
 MAMMMR

ABC DEF
AFBECD 
 MMAMMR

ABC  DEF
AFBECD  
 MMAA RR

ABCDEF 
AFB ECD
 MMR MA

 AB CDEF   // This doesn't make much sense,
AFBECD     // but it's to show leading spaces are also allowed
AM A  RR

Keine davon hat jedoch nur vier Änderungen, also nur A B CDEF\nAFBECD \n A A RR eine gültige Ausgabe für diese Herausforderung vorliegt.

Herausforderungsregeln:

  • Sie können davon ausgehen, dass die Eingabezeichenfolgen keine neuen Zeilen oder Leerzeichen enthalten.
  • Die beiden Eingabezeichenfolgen können unterschiedlich lang sein.
  • Eine der beiden Eingabezeichenfolgen sollte unverändert bleiben, mit Ausnahme von optionalen führenden / nachfolgenden Leerzeichen.
  • Wenn Ihre Sprachen nichts anderes als ASCII unterstützen, können Sie davon ausgehen, dass die Eingabe nur druckbare ASCII-Zeichen enthält.
  • Das Eingabe- und Ausgabeformat ist flexibel. Sie können drei separate Strings, ein String-Array, einen einzelnen String mit Zeilenumbrüchen, ein 2D-Zeichen-Array usw. haben.
  • Sie dürfen stattdessen etwas anderes verwenden ARM, aber geben Sie an , was Sie verwendet haben (z. B. 123oderabc. usw.).
  • Wenn mehr als eine gültige Ausgabe mit der gleichen Anzahl von Änderungen möglich ist (ARM ), können Sie auswählen, ob eine der möglichen Ausgaben oder alle davon ausgegeben werden sollen.
  • Führende und nachfolgende Leerzeichen sind optional:

    A B CDEF
    AFBECD
     A A  RR
    

    oder

    "A B CDEF\nAFBECD\n A A  RR"
                     ^
                     Note there are no spaces here
    

Allgemeine Regeln:

  • Das ist , also gewinnt die kürzeste Antwort in Bytes.
    Lassen Sie sich von Code-Golf-Sprachen nicht davon abhalten, Antworten mit Nicht-Codegolf-Sprachen zu veröffentlichen. Versuchen Sie, für jede Programmiersprache eine möglichst kurze Antwort zu finden.
  • Es gelten Standardregeln Ihre Antwort Daher dürfen Sie STDIN / STDOUT, Funktionen / Methode mit den richtigen Parametern und vollständige Programme verwenden. Ihr Anruf.
  • Standardlücken sind verboten.
  • Fügen Sie nach Möglichkeit einen Link mit einem Test für Ihren Code hinzu.
  • Fügen Sie ggf. auch eine Erklärung hinzu.

Testfälle:

In: "ABCDEF" & "AFBECD"

Output (4 changes):
A B CDEF
AFBECD  
 A A  RR                  

In: "This_is_an_example_text" & "This_is_a_test_as_example"

Possible output (13 changes):
This_is_an       _example_text
This_is_a_test_as_example     
         MAAAAAAA        RRRRR

In: "AaAaABBbBBcCcCc" & "abcABCabcABC"

Possible output (10 changes):
AaAaABBbBBcCcCc
 abcABCab cABC 
R MM  MMMR MM R

In: "intf(){longr=java.util.concurrent.ThreadLocalRandom.current().nextLong(10000000000L);returnr>0?r%2:2;}" & "intf(){intr=(int)(Math.random()*10);returnr>0?r%2:2;}"

Possible output (60 changes):
intf(){longr=java.util.concurrent.ThreadLocalRandom.current().nextLong(10000000000L);returnr>0?r%2:2;}
intf(){i ntr=(      i    n      t)(M  ath.r   andom        ()*         10          );returnr>0?r%2:2;}
       MR M  MRRRRRR RRRR RRRRRR MMMRR MMMMRRR     RRRRRRRR  MRRRRRRRRR  RRRRRRRRRR 

In: "ABCDEF" & "XABCDF"

Output (2 changes):
 ABCDEF
XABCD F 
A    R 

In: "abC" & "ABC"

Output (2 changes):
abC
ABC
MM 
Kevin Cruijssen
quelle
Related
Kevin Cruijssen
Wenn es mehrere Absprachen gibt, die den gleichen Abstand haben, ist es in Ordnung, nur eine davon auszugeben?
AdmBorkBork
@AdmBorkBork Ja, nur eine der möglichen Ausgaben ist tatsächlich die beabsichtigte Ausgabe (obwohl es auch in Ordnung ist, alle verfügbaren Optionen auszugeben). Ich werde dies in den Herausforderungsregeln klarstellen.
Kevin Cruijssen
@Arnauld Ich habe die Regel zu führenden Leerzeichen entfernt, sodass führende und nachfolgende Leerzeichen in der nicht geänderten Zeile optional und gültig sind. (Das heißt, der letzte Testfall in Ihrer Antwort ist vollständig gültig.)
Kevin Cruijssen
1
@Ferrybig Ah ok, danke für die Erklärung. Für diese Herausforderung reicht es jedoch bereits aus, druckbares ASCII zu unterstützen. Wenn Sie mehr unterstützen möchten, seien Sie mein Gast. Aber solange es für die gegebenen Testfälle funktioniert, bin ich mit undefiniertem Verhalten für Graphen-Cluster, die aus mehr als einem solchen Zeichen bestehen, einverstanden. :)
Kevin Cruijssen

Antworten:

5

Haskell , 192 181 174 161 158 150 147 143 158 1 Byte

e@(a:r)&f@(b:s)=snd$maximum[([1|' '<-s!!2],s)|s<-z(z(:))[a:" R",' ':b:"A",a:b:last("M":[" "|a==b])][r&f,e&s,r&s]]
x&y=[x,y,"RA"!!(0^length x)<$x++y]
z=zipWith

Probieren Sie es online! Beispiel Nutzung: "ABCDEF" & "AFBECD". Gibt eine Liste mit drei Zeichenfolgen zurück. Dies ist eine Erweiterung meiner rekursiven Lösung der gewöhnlichen Levenshtein-Distanzfrage .

Erläuterung:

Um die minimalen Änderungen zu berechnen, die von "xyz"zu kommen "yw", konzentrieren wir uns auf das erste Zeichen beider Zeichenfolgen. Es gibt drei Möglichkeiten:

  • Entfernen: Tropfen xaus der ersten Zeichenfolge und rekursiv die Änderungen berechnen bekommen von "yz"zu "yw". Dies ergibt die drei Linien ["yz","yw"," M"]. Fügen Sie xdem ersten ein Leerzeichen zum zweiten und Rzum dritten hinzu. Wir bekommen
    xyz
    yw
    RM
  • Add: Entferne yvon der zweiten Zeichenkette und berechne "xyz" & "w", was das Ergebnis ergibt ["xyz","w","MRR"]. Wir müssen in der ersten Zeile ein Leerzeichen einfügen, yin der zweiten undA in der dritten Zeile einfügen:
     xyz
    yw
    AMRR
  • Modifizierte / Unverändert: Wir können diese beiden Fälle kombinieren , da beide erfordern das erste Zeichen der beiden Strings fallen zu lassen und die minimalen Änderungen zwischen den verbleibenden Strings berechnen: "yz" & "w". Zum Ergebnis ["yz","w","MR"]fügen wir xin der ersten und yin der zweiten Zeile hinzu. Nur für die letzte Zeile müssen wir unterscheiden, ob die Anfangszeichen gleich sind. Wenn sie identisch sind, wird ein Leerzeichen in die dritte Zeile eingefügt, andernfalls wird (wie in diesem Fall, weil x \= y) Folgendes Mhinzugefügt:
    xyz
    yw
    MMR

Von diesen drei Kandidaten müssen wir den mit den wenigsten Änderungen finden. Dies entspricht den meisten Leerzeichen in der dritten Zeile. Daher konvertieren wir jeden Kandidaten s(eine Liste mit drei Zeichenfolgen) in ein Tupel ([1|' '<-s!!2],s), wobei sals zweite Komponente angezeigt wird und die erste Komponente eine Liste mit so vielen Elementen ist, wie Leerzeichen in der dritten Zeile von s( s!!2wegen der 0-Indizierung) vorhanden sind. Als Listenelement 1wird verwendet, aber das tatsächliche Element ist irrelevant, solange es für alle Kandidaten gleich ist.

Insgesamt ergibt dies die Liste der Tupel

[([1], [xyz, yw, RM]), ([], [xyz, yw, AMRR]), ([], [xyz, yw "," MMR "])]
Das Build-In maximumwählt das größte Element dieser Liste aus, in dem Tupel lexikografisch verglichen werden, dh komponentenweise von links nach rechts. Wenn [1]größer als [], wird das erste Tupel ausgewählt und snddas zweite der Komponente, dh der Liste der Zeilen, des Tupels zurückgegeben.


1 +15 Byte, um einen Fehler zu beheben, bei dem A-Änderungen am Ende einer Zeichenfolge als R-Änderungen angezeigt werden

Laikoni
quelle
Lol das lässt das UserScript denken, dass dies 1 Byte ist
HyperNeutrino
8

JavaScript (ES6), 413 ... 343 342 Byte

5 Bytes durch Optimieren der Schleifenindizes gespart, wie von @KevinCruijssen vorgeschlagen

Nimmt Eingaben als 2 Zeichenfolgen in der Currying-Syntax an. Gibt ein Array mit 3 Zeichenfolgen zurück.

b=>a=>{m=[];x=a.length;y=b.length;for(i=j=0,c=d='';i<=y;c+=R='R')m[i]=[[c,i++]];for(;j++<x;)m[i=0][j]=[d+=A='A',j];for(;i<y;i++)for(j=0;j<x;)[C]=m[[X,S]=m[i][j],[Y,I]=m[i+1][j],[Z,D]=m[i][++j],Q=[Z+R,D+1],i+1][j]=b[i]==a[j-1]?[X+' ',S]:S<I?D<S?Q:[X+'M',S+1]:D<I?Q:[Y+A,I+1];return[(g=s=>C.replace(/./g,c=>c==s?' ':b[i++],i=0))(A),g(R,b=a),C]}

Testfälle

Weniger golfen

b => a => {
  m = []; x = a.length; y = b.length;

  // initialize the leftmost column and the topmost row
  for(i = j = 0, c = d = ''; i <= y; c += R = 'R')
    m[i] = [[c, i++]];
  for(; j++ < x;)
    m[i = 0][j] = [d += A = 'A', j];

  // walk through the Levenshtein matrix
  for(; i < y; i++)
    for(j = 0; j < x;)
      [C] = m[                                // C = current string, once updated
        [X, S] = m[i][j],                     // substitution
        [Y, I] = m[i + 1][j],                 // insertion
        [Z, D] = m[i][++j],                   // deletion
        Q = [Z + R, D + 1],                   // precomputed update for deletion
        i + 1
      ][j] =
        b[i] == a[j - 1] ?
          [X + ' ', S]                        // unchanged character
        :
          S < I ?
            D < S ? Q : [X + 'M', S + 1]      // deletion or substitution
          :
            D < I ? Q : [Y + A, I + 1];       // deletion or insertion

  return [
    // g = helper function to format the output strings by inserting spaces
    (g = s => C.replace(/./g, c => c == s ? ' ' : b[i++], i = 0))(A),
    g(R, b = a),

    // final modification string, picked from the last visited cell
    C
  ]
}

Beispiel

Unten ist die anfängliche Matrix für b = "foo" und a = "ok" :

//                     'o'           'k'
[ [ [ '',    0 ], [ 'A',   1 ], [ 'AA',  2 ] ],
  [ [ 'R',   1 ],  (undefined),  (undefined) ],  // 'f'
  [ [ 'RR',  2 ],  (undefined),  (undefined) ],  // 'o'
  [ [ 'RRR', 3 ],  (undefined),  (undefined) ] ] // 'o'

und hier ist die endgültige Matrix nach allen Iterationen:

//                     'o'           'k'
[ [ [ '',    0 ], [ 'A',   1 ], [ 'AA',  2 ] ],
  [ [ 'R',   1 ], [ 'M',   1 ], [ 'MA',  2 ] ],  // 'f'
  [ [ 'RR',  2 ], [ 'R ',  1 ], [ 'R A', 2 ] ],  // 'o'
  [ [ 'RRR', 3 ], [ 'RR ', 2 ], [ 'R M', 2 ] ] ] // 'o'

Die endgültige Änderungszeichenfolge sowie der Levenshtein-Abstand werden in der rechten unteren Zelle gespeichert.

Arnauld
quelle
Gleiche Änderung vorgeschlagen , dass ich 1 Byte speichern in Bezug auf -1 / + 1 jund xgilt nach wie vor um Ihre neueste edit: b=>a=>{m=[];x=a.length;y=b.length+1;for(i=y;i--;)m[i]=[[i,'R'.repeat(i)]];for(j=x+1;j--;)m[i=0][j]=[j,'A'.repeat(j)];for(;++i<y;)for(j=-1;++j<x;)R=m[S=(X=m[i-1][j])[0],I=(Y=m[i][j])[0],D=(Z=m[i-1][j+1])[0],Q=[D+1,Z[1]+'R'],i][j+1]=b[i-1]==a[j]?[S,X[1]+' ']:S<I?D<S?Q:[S+1,X[1]+'M']:D<I?Q:[I+1,Y[1]+'A'];return[(g=s=>R[1].replace(/./g,c=>c==s?' ':b[i++],i=0))('A'),g('R',b=a),R[1]]}:)
Kevin Cruijssen
1
@KevinCruijssen Ich habe 5 Bytes gespart, indem ich Ihre Idee weiterentwickelt habe. Vielen Dank!
Arnauld
4

Python 2 , 548 536 484 500 1 488 447 381 2 373 371 357 350 Bytes

s,t=input()
n,m=len(s),len(t)
r=range
L=[[(j,'RA'[i<1]*j)for j in r(i,m-~i)]for i in r(n+1)]
for i in r(n):
 for j in r(m):M,R=L[i][j:j+2];A=L[i+1][j];v,V=min(A,R,M);x=('AR'[v in R],'M_'[s[i]==t[j]])[v in M];_=M;X=eval(x)[1]+x;L[i+1][j+1]=v+(x<'_'),X
for i in r(len(X)):s=s[:i]+' '*('B'>X[i])+s[i:];t=t[:i]+' '*('R'==X[i])+t[i:]
print s+'\n'+t+'\n'+X

Probieren Sie es online!

Verwendet 'ARM_' anstelle von'ARM '

Baut die Levenshtein-Matrix auf und geht dann rückwärts, um die Operationen zu finden . Bildet nun den Operationsstring gleichzeitig mit der Levenshtein-Matrix, wie in Arnauld's JS-Antwort

1: Mehr Bytes, da es nicht funktionierte, wenn die erste Zeichenfolge ein einzelnes Zeichen war.

2: Umstellung auf den Aufbau der Kombinationen in der Levenshtein-Matrix.

TFeld
quelle
+1 für weniger als 60 Sekunden für 6-
stellige
Gute Antwort! +1 von mir. Da ich nie in Python programmiere, kann ich Ihnen beim Golfen nicht wirklich weiterhelfen, abgesehen von einer Sache: m+i+1Kann sein m-~i.
Kevin Cruijssen
Sie können einen Tabulator anstelle von doppelten Leerzeichen in Zeile 7 verwenden.
Stephen
Sie können 463 Bytes erreichen, indem Sie die wile-Schleife auf eine Zeile reduzieren:while i+j<n+m:v,A=(L[i]+[m,m])[j:j+2];R,M=(L[i+1]+[m,m])[j:j+2];d=min(A,R,M);q=M==d or(R==d)*2;r+=' '*(d==v==M)or'AMR'[q];i+=q>0;j+=q<2
ovs
1

Python 2 , 310 Bytes

from difflib import*
a,b=input()
U,j=[],' '
for g,s,t,x,y in SequenceMatcher(0,a,b).get_opcodes():
	g,Y,T=g[0],y-x,t-s
	z,A,B=Y-T,a[s:t],b[x:y]
	if'q'<g:U+=[A+z*j,B+j*-z,'M'*min(T,Y)+'A'*z+'R'*-z]
	if'e'==g:U+=[A,B,j*Y]
	if'i'==g:U+=[j*Y,B,'A'*Y]
	if'e'>g:U+=[A,j*T,'R'*T]
for e in[0,1,2]:print''.join(U[e::3])

Probieren Sie es online!

Mit difflib.SequenceMatcherdiesem Befehl wird eine Ausrichtung zwischen zwei Zeichenfolgen berechnet

mdahmoune
quelle
Dies scheint für einige der anderen Testfälle zu falschen Ergebnissen zu führen. Insbesondere:"This_is_an_example_text","This_is_a_test_as_example"
Kevin Cruijssen
@ KevinCruijssen Danke, ich habe es gerade behoben ^ _ ^
mdahmoune
Schön, gj! Aber ähm ... der dritte Testfall (und auch der vierte) ist leider auch falsch. Eine der beiden Zeilen sollte unverändert bleiben (mit Ausnahme von führenden / nachfolgenden Leerzeichen). Beide Zeilen enthalten derzeit Leerzeichen in der Mitte.
Kevin Cruijssen
@ KevinCruijssen Danke nochmal, ich repariere es
mdahmoune
1

Mathematica, 250 256 259 384 Bytes

~ 0,00035 Sekunden für den Java-Code-Fall.

(i=o=p="";a=Array;r=StringLength;If[Length@#>0,g=#&@@#;h=#[[2]];u=r@g;v=r@h;i=i<>g;o=o<>h;w=Abs[v-u];k=a[" "&,w];If[u<v,i=i<>k,o=o<>k];p=p<>a["M"&,u~Min~v];p=p<>a[If[u>v,"R","A"]&,w],i=i<>#;o=o<>#;p=p<>a[" "&,r@#]]&/@SequenceAlignment[#,#2];{i,o,p})&

Verwendung: f["ABCDE", "ABCDF"]

Probieren Sie es online!

Der Code basiert auf einer Tatsache, SequenceAlignmentdie standardmäßig auf funktioniert

Bei der Standardeinstellung SimilarityRules-> Automatic trägt jede Übereinstimmung zwischen zwei Elementen 1 zur gesamten Ähnlichkeitsbewertung bei, während jede Nichtübereinstimmung, Einfügung oder Löschung -1 beiträgt.

Und zwar wird der Scoring berechnet M, Aund Rdementsprechend.

Beispiel:

Beispiel

Keyu Gan
quelle
2
Hmm, ich habe noch nie in Mathemetica programmiert, aber ist es nicht möglich , sich ändern i="";o="";p="";zu i="";o=i;p=i;2 Bytes zu reduzieren?
Kevin Cruijssen
2
Was ist i=o=p=""?
DavidC
@DavidC Ja das hatte ich gemerkt und schon geändert.
Trotzdem
1

D , 351 345 Bytes

-6 Bytes Danke an KevinCruijssen

string f(string a,string b){import std.algorithm;string x,y,z;size_t i,j,k;foreach(c;levenshteinDistanceAndPath(a,b)[1]){final switch(c)with(EditOp){case none:x~=a[i++];y~=b[j++];z~=" ";break;case substitute:x~=a[i++];y~=b[j++];z~="M";break;case insert:x~=" ";y~=b[j++];z~="A";break;case remove:x~=a[i++];y~=" ";z~="R";}}return x~"\n"~y~"\n"~z;}

Probieren Sie es online!

mdahmoune
quelle
Sie können sechs Bytes Golf spielen, indem Sie das letzte entfernen break;. +1 allerdings sehe ich zum ersten Mal die Programmiersprache D.
Kevin Cruijssen