我不喜欢改变!


19

输入:

两个没有换行符或空格的字符串。

输出:

两个输入字符串都在单独的行上,两个字符串之一之间在必要时加空格。并以字符的第三线ARM,代表添加删除修改,和改变

我们在顶部底部输入字符串中添加空格(如果需要)。这项挑战的目标是输出ARM尽可能少的变化量(),也称为Levenshtein距离

例:

假设输入字符串为ABCDEFAFBECD,则输出为:

A B CDEF
AFBECD  
 A A  RR

这里有一些其他可能的无效输出作为示例(还有很多):

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

但是,所有这些都没有四个更改,因此只有A B CDEF\nAFBECD \n A A RR一个有效的输出可用于此挑战。

挑战规则:

  • 您可以假设输入字符串不包含任何换行符或空格。
  • 两个输入字符串的长度可以不同。
  • 除可选的前导/尾随空格外,两个输入字符串之一应保持不变。
  • 如果您的语言除ASCII外不支持其他任何语言,则可以假定输入将仅包含可打印的ASCII字符。
  • 输入和输出格式灵活。您可以具有三个单独的字符串,一个字符串数组,带有换行符的单个字符串,2D字符数组等。
  • 您可以使用而不是来使用其他内容ARM,但要说明您使用过的内容(例如123,或abc.等)。
  • 如果在相同的更改量(ARM)下可能有多个有效输出,则可以选择是输出一个可能的输出还是全部输出。
  • 前导和尾随空格是可选的:

    A B CDEF
    AFBECD
     A A  RR
    

    要么

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

通用规则:

  • 这是,因此最短答案以字节为单位。
    不要让代码高尔夫球语言阻止您发布使用非代码高尔夫球语言的答案。尝试针对“任何”编程语言提出尽可能简短的答案。
  • 标准规则适用于您的答案,因此允许您使用STDIN / STDOUT,具有正确参数的函数/方法,完整程序。你的来电。
  • 默认漏洞是禁止的。
  • 如果可能,请为您的代码添加一个带有测试的链接。
  • 另外,如有必要,请添加说明。

测试用例:

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 


如果有多个相同距离的布置,可以只输出其中之一吗?
AdmBorkBork

@AdmBorkBork是的,只是可能的输出之一确实是预期的输出(尽管输出所有可用选项也可以)。我将在挑战规则中对此进行澄清。
凯文·克鲁伊森

@Arnauld我已经删除了有关前导空格的规则,因此前导空格和尾随空格都是可选的,并且在未修改的行上都是有效的。(这意味着您答案中的最后一个测试用例是完全有效的。)
Kevin Cruijssen

1
@Ferrybig啊,好的,谢谢您的解释。但是对于这个挑战,仅支持可打印的ASCII实际上已经足够了。如果您想支持更多,请成为我的客人。但是只要能在给定的测试用例下工作,我就可以确定由不止一个字符组成的石墨烯簇的不确定行为。:)
Kevin Cruijssen

Answers:


5

Haskell中192 181 174 161 158 150 147 143 158 1字节

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

在线尝试!用法示例:"ABCDEF" & "AFBECD"。返回三个字符串的列表。这是我对普通Levenshtein距离问题的递归解决方案的扩展。

说明:

为了计算从"xyz"到的最小修改量"yw",我们关注两个字符串的第一个字符。有三种可能性:

  • 删除:x从第一个字符串中删除,然后递归计算从"yz"到的修改"yw"。这产生了三行["yz","yw"," M"]x在第一个添加一个,第二个和R第三个添加一个空格。我们得到
    y
    w
    R M
  • 添加:y从第二个字符串中删除并进行计算"xyz" & "w",这将返回结果["xyz","w","MRR"]。我们需要在第一行,y第二行和A第三行上添加一个空格:
     y
    w
    AMRR
  • 修改/不变:我们可以将这两种情况结合起来,因为两者都需要删除两个字符串的第一个字符并计算其余字符串之间的最小修改:"yz" & "w"。作为结果["yz","w","MR"],我们x在第一行和y第二行上添加他。仅对于最后一行,我们需要区分初始字符是否相同。如果它们相同,则在第三行添加一个空格,否则(在这种情况下,因为x \= yM被添加为:
    y
    w
    MMR

从这三个候选人中,我们需要找到修改最少的候选人。这等效于在第三行上具有最多的空格。因此,我们将每个候选项s(三个字符串的列表)转换为一个元组([1|' '<-s!!2],s),在其中s显示为第二个成分,而第一个成分是一个列表,其中元素的数量与ss!!2由于0索引)的第三行中的空格一样多。1使用list元素,但实际元素无关紧要,只要所有候选元素都相同即可。

总而言之,这产生了元组列表

[([[1],[“ xyz”,“ yw”,“ RM”]),([[,, [“ xyz”,“ yw”,“ AMRR”]),([],[“ xyz”,“ yw“,” MMR“])]
内置程序maximum选择此列表中最大的元素,在这里按字典顺序比较元组,即从左到右按组件方式比较。如[1]大于[],则选择第一个元组,并snd返回第二个组成部分,即该元组的行列表。


1 +15个字节来修复一个错误,该错误在A字符串末尾的R-changes 将显示为-changes


大声笑这使用户脚本认为这是1个字节
HyperNeutrino

8

JavaScript(ES6),413 ... 343342字节

通过调整循环索引,节省了5个字节,如@KevinCruijssen所建议

使用currying语法将输入作为2个字符串。返回3个字符串的数组。

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

测试用例

少打高尔夫球

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

以下是b =“ foo”a =“ ok”的初始矩阵:

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

这是所有迭代后的最终矩阵:

//                     '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'

最终的修改字符串以及Levenshtein距离都存储在右下角的单元格中。


相同的更改,我建议保存有关-1 / + 1的1个字节,j并且x仍然适用于您的最新编辑: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通过将您的想法更进一步,我节省了5个字节。谢谢!
Arnauld

4

Python 2中548 536 484 500 1 488 447 381 2个 373 371 357 350字节

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

在线尝试!

'ARM_'代替'ARM '

通过建立Levenshtein矩阵进行工作,然后向后遍历以找到操作。现在与Levenshtein矩阵同时构建操作字符串,如Arnauld的JS答案

1:更多的字节,因为如果第一个字符串是单个字符,它将不起作用。

2:切换到在Levenshtein矩阵中构建组合。


+1表示我花了不到60秒的时间来输入6个字符的单词,例如我的初次尝试(失败)大声笑
HyperNeutrino

好答案!向我+1。由于我从不使用Python编程,因此我无法真正帮助您打高尔夫球,除了一件事:m+i+1可以m-~i
凯文·克鲁伊森

您可以在第7行使用制表符代替双倍空格
斯蒂芬·

您可以通过将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
wile

1

Python 2,310字节

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])

在线尝试!

使用difflib.SequenceMatcher它来计算两个字符串之间的对齐方式


对于其他一些测试用例,这似乎给出了一些不正确的结果。更特别的是:"This_is_an_example_text","This_is_a_test_as_example"
Kevin Cruijssen

@KevinCruijssen thanx,我刚刚修复了它^ _ ^
mdahmoune

太好了!但是不幸的是,第三个测试用例(以及第四个测试用例)也是不正确的。两行之一应保持不变(前导/后跟空格除外)。当前两行中间都包含空格。
凯文·克鲁伊森

@KevinCruijssen thanx再次,我正在解决它
mdahmoune

1

Mathematica,250 256 259 384 个字节

Java代码案例为〜0.00035秒。

(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})&

用法: f["ABCDE", "ABCDF"]

在线尝试!

该代码基于以下事实:SequenceAlignment默认情况下,

使用默认设置“相似性规则”->“自动”,两个元素之间的每个匹配对总相似性得分贡献1,而每个不匹配,插入或删除则贡献-1。

即,得分由下式计算MAR,相应地。

例:

例


2
嗯,我从来没有在Mathemetica编程,但不能够改变i="";o="";p="";,以i="";o=i;p=i;减少2个字节?
凯文·克鲁伊森

2
i=o=p=""
DavidC

@DavidC是的,我已经意识到这一点,并且已经对其进行了更改。无论如何,谢谢你
Keyu Gan

1

D351345字节

-6字节thanx到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;}

在线尝试!


您可以删除最后一个来打高尔夫球六个字节break;。+1虽然,我第一次看到的编程语言D.
凯文Cruijssen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.