代码在文末!
因为有学弟问我这个问题,所以来补充几句说明。 可能很多人会找到下面这幅图:
首先要说明我的代码(见本文末尾)是copy加5分,add和delete加20分。但是上图中应该是copy不算分,add和delete算一次编辑。无论怎么赋分,写成代码其实是一样的,只不过分值处改一改而已。此图上方是已有单词,左边是待生成的单词,而数字就是编辑次数(add和delete)。
每次单词转换都是从表格左上方“走”到表格右下方的过程:add是向下一格,delete是向右一格,copy是向右下一格。
其实很好理解:当前格对应的上字母和左字母正是当前正在处理的字母,如果发现相同就copy,原单词和生成单词各进一个字母,转而判断下一个字母的处理。如果不同就可以看看后面是不是有相同的,如果有很多相同的就可以delete掉原单词中间的不同字母或者add上生成单词的中间不同的字母,后面直接copy。
(举个例子,为了使编辑次数最小。当disagree到agree,果断扔掉前三个然后一通copy啊。acdfg转换到accdfg,果断中间add一个c然后copy其余啊。)
当然,情况复杂的时候是不能直接判断该采取什么措施的,这也是为什么需要这个程序来计算各种可能,找到最小的编辑路径。这道题本身完全不难,只要理解怎么在格子间移动就好。比较坑的是很多题目的分值不一样,有时候copy算分有时候不算。虽然本质完全一样,但是初学的时候很容易以为在讲完全一样的一道题,从而产生误解。
再贴几张图:
这个就是copy、add、delete都算一次......
代码:
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
if not self.isEmpty():
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
def replace(s1,s2,len1,len2):
mylist = [[0 for j in range(len2+1)] for i in range(len1+1)]#初始化mylist
mywork = [[None for j in range(len2+1)] for i in range(len1+1)]#初始化mywork
for i in range(1,len1+1):
mywork[i][0]="delete"
mylist[i][0]= 20*i
for j in range(1,len2+1):
mywork[0][j]="add"
mylist[0][j]= 20*j
#mywork用于储存最佳路径,记录如何到达此位置时
for i in range(1,len1+1):
for j in range(1,len2+1):
copy = mylist[i-1][j-1] + 5#copy相当于向右下移一格
add = mylist[i][j-1] + 20#add相当于下移一格
delete = mylist[i-1][j] + 20#delete相当于右移一格
if s1[i-1] == s2[j-1] and (copy<add and copy<delete):#只有当对应字母相同时才可以copy,字母编号从0开始
mylist[i][j] = copy
mywork[i][j] = "copy"
elif add>delete:
mylist[i][j] = delete
mywork[i][j] = "delete"
else:
mylist[i][j] = add
mywork[i][j] = "add"
print(mylist[len1][len2])
return mywork
def get_routine(mywork,l1,l2):
s=Stack()
while l1>0:
s.push(mywork[l1][l2])
if mywork[l1][l2]=="copy":
l1,l2=l1-1,l2-1
elif mywork[l1][l2]=="add":
l2=l2-1
elif mywork[l1][l2]=="delete":
l1=l1-1
while l2>0:#有时可能走到“边界上”,还需要再向上“回溯”
s.push("add")
l2=l2-1
while s.size()>0:
print(s.pop())
s1=input()
s2=input()
len1 = len(s1)
len2 = len(s2)
get_routine(replace(s1,s2,len1,len2),len1,len2)