最长公共子序列的界限

时间:2013-12-10 21:21:25

标签: python

我需要找到递归最长公共子序列问题(仅它的长度)的最紧密边界(对于最坏情况)。我的意思是复杂性以m和n为界,m是字符串s的长度,n是字符串t的长度。有人可以帮帮我吗?

代码是:

def lcs_len_v1(s, t): 
    n = len(s)
    m = len(t)
    return lcs_len_rec(s,n,t,m)

def lcs_len_rec(s,size_s,t,size_t):

    if size_s==0 or size_t==0: #if one of the strings is empty
        return 0

    if s[0] == t[0]: #if we find a common char
        return lcs_len_rec(s[1:],len(s[1:]), t[1:],len(t[1:]))+1
    else:
        return max(lcs_len_rec(s,len(s),t[1:],len(t[1:])), lcs_len_rec(s[1:],len(s[1:]),t,len(t)))

2 个答案:

答案 0 :(得分:1)

这是我用Python编写的最快的实现:

def lcs(x, y):
    '''returns the length of longest common subsequence of x and y.
       >>> lcs('abcde','aebd')
       3
    '''
    s_x, s_y = len(x), len(y)
    if s_x>s_y: 
        x, y = y, x
        s_x, s_y = s_y, s_x
    y_previous = s_x*[0]
    for y_char in y:
        left_value = 0
        diagonal_value = 0
        n=0
        for x_char in x:
            up_value = y_previous[n]
            if y_char==x_char:
                left_value = diagonal_value+1
            else:
                if left_value<up_value: 
                    left_value = up_value 
            diagonal_value = up_value
            y_previous[n] = left_value 
            n+=1
    return y_previous[-1]

如果您想提高性能,可以使用Cython进行编译。它的运行速度提高了90倍!

cimport cython
from libc.stdlib cimport malloc, free

def lcs(x, y):
    cdef int s_x
    cdef int s_y
    s_x, s_y = len(x), len(y)
    if s_x>s_y: 
        x, y = y, x
        s_x, s_y = s_y, s_x

    cdef int i

    temp_y_previous = s_x*[0]
    cdef int *y_previous
    y_previous = <int *>malloc(s_x*cython.sizeof(int))
    if y_previous is NULL:
        raise MemoryError()
    for i in xrange(s_x):
        y_previous[i] = temp_y_previous[i]

    cdef char *cx
    cx = <char *>malloc(s_x*cython.sizeof(char))
    if cx is NULL:
        raise MemoryError()
    i=0
    for character in x:
        cx[i]=ord(character)
        i+=1

    cdef char *cy
    cy = <char *>malloc(s_y*cython.sizeof(char))
    if cy is NULL:
        raise MemoryError()
    i=0
    for character in y:
        cy[i]=ord(character)
        i+=1

    cdef int k=0
    cdef int left_value
    cdef int diagonal_value
    cdef int n
    cdef str y_char
    cdef str x_char
    while k<s_y:
         left_value = 0
         diagonal_value = 0
         n=0
         while n<s_x:
             if cy[k]==cx[n]:
                 left_value = diagonal_value+1
             else:
                 if left_value<y_previous[n]:
                     left_value = y_previous[n]
             diagonal_value = y_previous[n]
             y_previous[n] = left_value 
             n+=1
         k+=1
    with nogil:
        free(y_previous)
        free(cx)
        free(cy)  
    return y_previous[s_x-1]

答案 1 :(得分:0)

我认为这会奏效。但我也认为长琴弦很慢。

def max_common_str_len(s, t):
     if len(s) > len(t):
         return max_common_str_len(t, s)
     for length in range(len(s),0,-1):
         for offset in range(len(s)-length+1):
             if s[offset:offset+length] in t:
                 return length
     else:
         return 0

max_common_str_len('there is a house in new orleans', 'this is a house')

<强>输出

11

修改

我还试验了你的代码。我认为它对于中等字符串来说很慢,因为你的函数使用相同的参数调用lcs_len_rec - 函数。考虑使用装饰器缓存/记忆它:

import functools

@functools.lru_cache(maxsize=None)
def lcs_len_rec(###your code###