【问题标题】:How do i make this function return what the Longest common subsequence(not the length of lcs)我如何让这个函数返回最长的公共子序列(不是 lcs 的长度)
【发布时间】:2021-12-14 11:51:52
【问题描述】:

hi 正在解决这个问题,我必须返回最长的公共子序列(lcs)有多长,并且我能够形成一个执行相同操作的递归函数,但现在我想知道如何让这个函数返回 lcs 是什么. 例如 seq1 = 'serendipitous' seq2 = 'precipitation' lcs of seq1 and seq2 is - reipito

我想做一个返回'reipito'的函数

我写的返回lcs长度的函数是

def lcs_recursive(seq1, seq2, idx1 = 0, idx2 = 0):
    
    if idx1 == len(seq1) or idx2 == len(seq2):
        return 0 
        
    if seq1[idx1] == seq2[idx2]:
        return 1 + lcs_recursive(seq1, seq2, idx1 + 1, idx2 + 1)
    
    else:
        option1 = lcs_recursive(seq1, seq2, idx1 + 1, idx2)
        option2 = lcs_recursive(seq1, seq2, idx1, idx2 + 1)
        
        return max(option1, option2)

这个函数如何返回lcs的长度

我厌倦了这样做但失败了。请帮忙

【问题讨论】:

标签: python recursion dsa


【解决方案1】:

只需对您的代码进行最少的更改:

def lcs_recursive(seq1, seq2, idx1 = 0, idx2 = 0, lcs = ''):
    
    if idx1 == len(seq1) or idx2 == len(seq2):
        return lcs
        
    if seq1[idx1] == seq2[idx2]:
        return lcs_recursive(seq1, seq2, idx1 + 1, idx2 + 1, lcs + seq1[idx1])
    
    else:
        option1 = lcs_recursive(seq1, seq2, idx1 + 1, idx2, lcs)
        option2 = lcs_recursive(seq1, seq2, idx1, idx2 + 1, lcs)
        
        return max(option1, option2, key=len)

seq1 = 'serendipitous'
seq2 = 'precipitation'
print(lcs_recursive(seq1, seq2)) # reipito

由于您可能多次使用相同的索引对调用 lcs_recursive,因此如果使用 Python >= 3.9 则 functools.cache 或如果使用 Python >= 3.2 则 functools.lru_cache 可能会提高性能。

例如,如果seq1 = 'ab'seq2 = 'bd'lcs_recursive('ab', 'bd') 最终将调用lcs_recursive('ab', 'bd', 2, 1) 两次(您可以通过在函数中执行print(idx1, idx2) 的第一件事来看到这一点)。使用下面的@lru_cache 优化,在第一次调用(idx1=2, idx2=1)(即lcs_recursive('ab', 'bd', 2, 1))时,计算并存储与(idx1=2, idx2=1) 对应的结果(在缓存中,您可以将其视为字典)。在随后调用同一索引对 ((idx1=2, idx2=1)) 时,会查找存储的结果,因此不必重新计算。一般来说,lru_cache 会根据输入来记忆结果。这就是为什么在下面的代码中,函数helper 只需要idx1idx2 - 以使lru_cache 更容易正常工作。

from functools import lru_cache

def lcs_recursive(seq1, seq2):
    @lru_cache
    def helper(idx1 = 0, idx2 = 0):
    
        if idx1 == len(seq1) or idx2 == len(seq2):
            return ''
            
        if seq1[idx1] == seq2[idx2]:
            return  seq1[idx1] + helper(idx1 + 1, idx2 + 1)
        
        option1 = helper(idx1 + 1, idx2)
        option2 = helper(idx1, idx2 + 1)
        
        return max(option1, option2, key=len)
    
    return helper()

seq1 = 'serendipitous'
seq2 = 'precipitation'
print(lcs_recursive(seq1, seq2)) # reipito

作为比较,seq1 = 'serendipitous'seq2 = 'precipitation' lcs_recursive_uncached(seq1, seq2) 进行 1119564 次递归调用,而 lcs_recursive_cached(seq1, seq2) 仅进行 184 次递归调用!:

number_of_calls_uncached = 0
def lcs_recursive_uncached(seq1, seq2, idx1 = 0, idx2 = 0, lcs = ''):
    global number_of_calls_uncached
    number_of_calls_uncached += 1

    if idx1 == len(seq1) or idx2 == len(seq2):
        return lcs
        
    if seq1[idx1] == seq2[idx2]:
        return lcs_recursive_uncached(seq1, seq2, idx1 + 1, idx2 + 1, lcs + seq1[idx1])
    
    else:
        option1 = lcs_recursive_uncached(seq1, seq2, idx1 + 1, idx2, lcs)
        option2 = lcs_recursive_uncached(seq1, seq2, idx1, idx2 + 1, lcs)
        
        return max(option1, option2, key=len)

seq1 = 'serendipitous'
seq2 = 'precipitation'
print(number_of_calls_uncached) # 0
print(lcs_recursive_uncached(seq1, seq2)) # reipito
print(number_of_calls_uncached) # 1119564


from functools import lru_cache

number_of_calls_cached = 0
def lcs_recursive_cached(seq1, seq2):
    @lru_cache
    def helper(idx1 = 0, idx2 = 0):
        global number_of_calls_cached
        number_of_calls_cached += 1

        if idx1 == len(seq1) or idx2 == len(seq2):
            return ''
            
        if seq1[idx1] == seq2[idx2]:
            return  seq1[idx1] + helper(idx1 + 1, idx2 + 1)
        
        option1 = helper(idx1 + 1, idx2)
        option2 = helper(idx1, idx2 + 1)
        
        return max(option1, option2, key=len)
    
    return helper()

seq1 = 'serendipitous'
seq2 = 'precipitation'
print(number_of_calls_cached) # 0
print(lcs_recursive_cached(seq1, seq2)) # reipito
print(number_of_calls_cached) # 184

【讨论】:

  • 感谢先生的详细解释 :) btw in return max(option1, option2, key=len) key= len 意味着 max 将返回具有最长长度的选项吗???
  • 是的,完全正确。例如。 print(max('Jack', 'Kilby', key=len)) 打印 Kilby,更长的字符串。
  • 非常感谢先生
【解决方案2】:

将发布的代码转换为返回 LCS 而不是长度。

def lcs_recursive(seq1, seq2, idx1 = 0, idx2 = 0):
    
    if idx1 == len(seq1) or idx2 == len(seq2):
        return ""
        
    if seq1[idx1] == seq2[idx2]:
        return  seq1[idx1] + lcs_recursive(seq1, seq2, idx1 + 1, idx2 + 1)
    
    else:
        option1 = lcs_recursive(seq1, seq2, idx1 + 1, idx2)
        option2 = lcs_recursive(seq1, seq2, idx1, idx2 + 1)
        
        
        return max(option1, option2, key = len)
                   
                   

测试

seq1 = 'serendipitous' 
seq2 = 'precipitation'
                   
print(lcs_recursive(seq1, seq2))
# Output: 'reipito'

【讨论】:

  • here in ``` return max(option1, option2, key = len) ``` key = len 表示 max 将返回字符串长度的最大值,对吧?
  • @ShivaKharbanda -- 它将返回最长的字符串。例如:max('zz', 'aaa', key = len) 是“aaa”。但是,max('zz', 'aaa') 是“zz”。
  • 非常感谢先生
猜你喜欢
  • 1970-01-01
  • 2012-11-23
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 2012-08-29
  • 2021-04-28
  • 2013-04-13
  • 2011-03-01
相关资源
最近更新 更多