【问题标题】:find the longest sequence S that is a subsequence of A,B,C string找到最长的序列 S,它是 A,B,C 字符串的子序列
【发布时间】:2011-01-16 12:17:11
【问题描述】:

给出一个多项式时间算法,它以三个字符串 A、B 和 C 作为输入,并返回最长的序列 S,它是 A、B 和 C 的子序列。

【问题讨论】:

  • 在其他人为您解决问题之前,请为您和他人付出一些努力——您尝试过什么?你被困在哪里了?你找到指数时间算法了吗?
  • @Elmi:你了解简单的 2 弦变奏是如何工作的吗?
  • 什么是“动态规划”?
  • @bestsss:意思是“在 Google 中输入准确的评论并查看出现的第一个结果”。
  • @j_random_hacker 我知道它应该是什么,我想知道它是如何进入标签的(如果你不知道如何解决这个问题,标签本身就是一个小奇迹)

标签: algorithm dynamic-programming


【解决方案1】:

dp[i, j, k] = longest common subsequence of prefixes A[1..i], B[1..j], C[1..k]

我们有:

dp[i, j, k] = dp[i - 1, j - 1, k - 1] + 1 if A[i] = B[j] = C[k]
              max(dp[i - 1, j, k], dp[i, j - 1, k], dp[i, j, k - 1]) otherwise

类似于 2d 的情况,除了你有 3 个维度。复杂度是O(len A * len B * len C)

【讨论】:

  • 这只会找到 LCS 长度而不是 LCS 本身。顺便说一句,你忘了dp[i,j,k] = 0 if i == 0 or j == 0 or k == 0
  • @J.F.塞巴斯蒂安 - 是的,但我想我也会留一点让 OP 弄清楚:)。
  • @IVlad 不能使用 2D dp 来完成,首先是字符串 1 和 2 ,然后是它们的 LCS 和字符串 3 吗? ...由此我们将只需要 O(N^2) 时间和空间。
  • @ac_c0der - 如果有多个 LCS,你会选择哪个?
  • @IVlad 我的意思是第一次找到 str1 和 str2 的 LCS。 let their LCS be X . 然后再次找到 X 和 str3 的 LCS,这将给出最终答案。 say LCS ( str1 and str2 and str3 ) `=` a units , then LCS ( str1 and str2 ) `>=` a units , if(LCS ( str1 and str2 ) `>` a units) then (LCS( X and str3) ) 将是== a units。
【解决方案2】:

这是 Python 中任意数量序列的解决方案。您可以使用它来测试 2D、3D 案例的解决方案。它紧跟Wikipedia's algorithm

#!/usr/bin/env python
import functools
from itertools import starmap

@memoize
def lcs(*seqs):
    """Find longest common subsequence of `seqs` sequences.
    
    Complexity: O(len(seqs)*min(seqs, key=len)*reduce(mul,map(len,seqs)))    
    """
    if not all(seqs):  return () # at least one sequence is empty
    heads, tails = zip(*[(seq[0], seq[1:]) for seq in seqs])
    if all(heads[0] == h for h in heads): # all seqs start with the same element
        return (heads[0],) + lcs(*tails)
    return max(starmap(lcs, (seqs[:i]+(tails[i],)+seqs[i+1:]
                             for i in xrange(len(seqs)))), key=len)
def memoize(func):
    cache = {}
    @functools.wraps(func)
    def wrapper(*args):
        try: return cache[args]
        except KeyError:
            r = cache[args] = func(*args)
            return r
    return wrapper

注意:没有记忆是指数算法(wolfram alpha):

$ RSolve[{a[n] == K a[n-1] + K, a[0] = K}, a[n], n]
a(n) = (K^(n + 1) - 1) K/(K - 1)

K == len(seqs)n == max(map(len, seqs))

示例

>>> lcs("agcat", "gac")
('g', 'a')
>>> lcs("banana", "atana")
('a', 'a', 'n', 'a')
>>> lcs("abc", "acb")
('a', 'c')
>>> lcs("XMJYAUZ", "MZJAWXU")
('M', 'J', 'A', 'U')
>>> lcs("XMJYAUZ")
('X', 'M', 'J', 'Y', 'A', 'U', 'Z')
>>> lcs("XMJYAUZ", "MZJAWXU", "AMBCJDEFAGHI")
('M', 'J', 'A')
>>> lcs("XMJYAUZ", "MZJAWXU", "AMBCJDEFAGUHI", "ZYXJAQRU")
('J', 'A', 'U')
>>> lcs() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ValueError:
>>> lcs(*"abecd acbed".split())
('a', 'b', 'e', 'd')
>>> lcs("acd", lcs("abecd", "acbed"))
('a', 'd')
>>> lcs(*"abecd acbed acd".split())
('a', 'c', 'd')

【讨论】:

    【解决方案3】:

    你所要做的就是谷歌“最长子序列”。

    这是顶部链接:http://en.wikipedia.org/wiki/Longest_common_subsequence_problem

    如果您对理解有任何特殊问题,请在此处提问,最好提出更具体的问题。

    【讨论】:

    • 这无法解决,因为它只涉及 2 个字符串。 “你了解更简单的 2 弦变奏是如何工作的吗?” by j_random_hacker 的意思完全一样
    • 算法很容易扩展为 3 个字符串。您只需将表格设为 3 维而不是 2。如果您了解两个字符串算法,那么它应该是有意义的。
    • >>您只是将表格设为 3 维而不是 2 维。
    • 我没有破坏任何东西。他/她仍然需要编写和理解算法。我所说的并不能减轻他/她做作业的负担。
    • 我并没有说没有工作要做,但是您从问题中消除了令人振奋的时刻,这是人们将要成长的地方。现在剩下的只是机械的。
    猜你喜欢
    • 2014-12-04
    • 1970-01-01
    • 2018-05-13
    • 2017-03-02
    • 2012-10-15
    • 2014-11-12
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多