这是一个可接受的算法吗?

时间:2012-12-31 23:17:09

标签: python lcs

我设计了一种算法来查找最长的公共子序列。这些是步骤:

  • 选择第一个字符串中的第一个字母。

  • 在第二个字符串中查找它,如果找到它,请将该字母添加到 common_subsequence并将其位置存储在index中,否则 将common_subsequence的长度与lcs的长度进行比较 如果它更大,则将其值设为lcs

  • 返回第一个字符串并选择下一个字母并重复 上一步,但这一次从index字母

  • 开始搜索
  • 重复此过程,直到第一个字符串中没有字母为止 挑。最后,lcs的值是最长的共同点 亚序列。

这是一个例子:

X=A, B, C, B, D, A, B‬‬  
‫‪Y=B, D, C, A, B, A‬‬ 

在第一个字符串中选择AA中查找Y 现在第二个字符串中有A,请将其附加到common_subsequence 返回第一个字符串并选择下一个B字母。 这次从B的位置开始,在第二个字符串中查找AB之后有一个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

2 个答案:

答案 0 :(得分:10)

如果您的教授希望您发明自己的LCS算法,那么您就完成了。你的算法并不是有史以来最优的算法,但它是在正确的复杂性类中,你清楚地理解它,你显然没有从互联网上复制你的实现。您可能希望准备好捍卫您的算法,或讨论替代方案。如果我是你的教授,我会给你一个A if:

  • 你上交了那个程序。
  • 您能够解释为什么没有可能的O(N)或O(N log M)替代方案。
  • 您能够参与有关其他算法的合理讨论,这些算法可能具有更好的更低界限(或显着更低的常数等),以及时间/空间权衡等,甚至如果您事先不知道该讨论的结果。

另一方面,如果您的教授希望您选择一种众所周知的算法并编写自己的实现,您可能希望使用标准的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