我设计了一种算法来查找最长的公共子序列。这些是步骤:
选择第一个字符串中的第一个字母。
在第二个字符串中查找它,如果找到它,请将该字母添加到
common_subsequence
并将其位置存储在index
中,否则
将common_subsequence
的长度与lcs
的长度进行比较
如果它更大,则将其值设为lcs
。
返回第一个字符串并选择下一个字母并重复
上一步,但这一次从index
字母
重复此过程,直到第一个字符串中没有字母为止
挑。最后,lcs
的值是最长的共同点
亚序列。
这是一个例子:
X=A, B, C, B, D, A, B
Y=B, D, C, A, B, A
在第一个字符串中选择A
在A
中查找Y
现在第二个字符串中有A
,请将其附加到common_subsequence
返回第一个字符串并选择下一个B
字母。
这次从B
的位置开始,在第二个字符串中查找A
在B
之后有一个A
,因此将B附加到common_subsequence
现在选择第一个字符串C
中的下一个字母。第二个字符串中C
旁边没有B
。因此,将common_subsequence的值赋给lcs
,因为它的长度大于lcs
的长度。
重复前面的步骤,直到到达第一个字符串的末尾。最后,lcs
的值是最长公共子序列。
该算法的复杂性是theta(n * m)。 这是我的实现:
第一种算法:
import time
def lcs(xstr, ystr):
if not (xstr and ystr): return # if string is empty
lcs = [''] # longest common subsequence
lcslen = 0 # length of longest common subsequence so far
for i in xrange(len(xstr)):
cs = '' # common subsequence
start = 0 # start position in ystr
for item in xstr[i:]:
index = ystr.find(item, start) # position at the common letter
if index != -1: # if common letter has found
cs += item # add common letter to the cs
start = index + 1
if index == len(ystr) - 1: break # if reached end of the ystr
# update lcs and lcslen if found better cs
if len(cs) > lcslen: lcs, lcslen = [cs], len(cs)
elif len(cs) == lcslen: lcs.append(cs)
return lcs
file1 = open('/home/saji/file1')
file2 = open('/home/saji/file2')
xstr = file1.read()
ystr = file2.read()
start = time.time()
lcss = lcs(xstr, ystr)
elapsed = (time.time() - start)
print elapsed
使用哈希表的相同算法:
import time
from collections import defaultdict
def lcs(xstr, ystr):
if not (xstr and ystr): return # if strings are empty
lcs = [''] # longest common subsequence
lcslen = 0 # length of longest common subsequence so far
location = defaultdict(list) # keeps track of items in the ystr
i = 0
for k in ystr:
location[k].append(i)
i += 1
for i in xrange(len(xstr)):
cs = '' # common subsequence
index = -1
reached_index = defaultdict(int)
for item in xstr[i:]:
for new_index in location[item][reached_index[item]:]:
reached_index[item] += 1
if index < new_index:
cs += item # add item to the cs
index = new_index
break
if index == len(ystr) - 1: break # if reached end of the ystr
# update lcs and lcslen if found better cs
if len(cs) > lcslen: lcs, lcslen = [cs], len(cs)
elif len(cs) == lcslen: lcs.append(cs)
return lcs
file1 = open('/home/saji/file1')
file2 = open('/home/saji/file2')
xstr = file1.read()
ystr = file2.read()
start = time.time()
lcss = lcs(xstr, ystr)
elapsed = (time.time() - start)
print elapsed
答案 0 :(得分:10)
如果您的教授希望您发明自己的LCS算法,那么您就完成了。你的算法并不是有史以来最优的算法,但它是在正确的复杂性类中,你清楚地理解它,你显然没有从互联网上复制你的实现。您可能希望准备好捍卫您的算法,或讨论替代方案。如果我是你的教授,我会给你一个A if:
另一方面,如果您的教授希望您选择一种众所周知的算法并编写自己的实现,您可能希望使用标准的LP算法。这是一个标准算法,出于某种原因 - 您可能希望在您理解之前阅读它。 (即使它不会参加考试,你也要上这门课来学习,不仅仅是为了给教授留下深刻的印象,对吗?)
Wikipedia具有基本实现的伪代码,然后是常用优化的英语描述。我很确定根据该页面上的内容编写自己的Python代码不会算作抄袭,甚至不算作一个简单的端口,特别是如果你能证明你明白你的代码在做什么,为什么,以及为什么这是一个很好的算法。另外,你用Python编写它,它比那篇文章中演示的更好的记忆方式,所以如果你理解它是如何工作的,那么你的代码实际上应该比维基百科给你的好得多。
无论哪种方式,正如我在评论中所建议的那样,我会阅读Bergroth,Hakonen和Raita的A survey of longest common subsequence algorithms,并在线搜索类似的论文。
答案 1 :(得分:-4)
maxLength = 0
foundString = ""
for start in xrange(len(str1)-1):
for end in xrange(start+1, len(str1)):
str1Temp = str1[start:end]
maxLengthTemp = len(str1Temp)
if(str2.find(str1Temp)):
if(maxLengthTemp>maxLength):
maxLength = maxLengthTemp
foundString = str1Temp
print maxLength
print foundString