最长公共子序列问题

假设有两个序列S1[1...m]和S2[1...n],需要寻找它们之间的一个最长公共子序列。
例如,假定我们有如下两个序列:
S1:I N T H E B E G I N N I N G
S2:A L L T H I N G S A R E L O S T
则S1和S2的一个最长公共子序列为THING。又如:
S1:A B C B D A B
S2:B D C A B A
则S1和S2的一个最长公共子序列为BCBA。
这里需要注音的是,一个子序列不一定必须是连续的,中间可以被其他字符分开。最长公共子序列不一定只有一个,而我们要寻找的是其中一个。
设c[i, j] = LCS(S1[1...i], S2[1...j]) ,表示S1[1...i]和S2[1...j]的最长子序列。那么问题的解为c[m, n]。
仔细观察我们可以知道:
如果S1[i] = S2[j],那么c[i, j] = c[i-1, j-1] + 1,
如果S1[i] ≠ S2[j],那么c[i, j] = max{c[i-1, j], c[i, j-1}(证明略)。那么我们就将原问题分解为相似的子问题。而子问题很多是重复的,所以我们将子问题的结果存放到表中,防止重复计算。
最长公共子序列的Python代码如下:

#!/usr/bin/python
# -*- coding: utf8 -*-
 
S1 = ['I', 'T', 'E', 'I', 'N', 'G']
S2 = ['T', 'I', 'N', 'G', 'E']
 
#后面几组供测试使用
#S1 = ['A', 'N', 'T', 'H']
#S2 = ['A', 'L', 'N', 'T']
 
#S1 = ['I', 'N', 'T', 'H', 'E', 'B', 'E', 'G']
#S2 = ['A', 'L', 'L', 'T', 'H', 'I', 'N', 'G']
 
#S1 = ['A', 'B', 'C', 'B', 'D', 'A', 'B']
#S2 = ['B', 'D', 'C', 'A', 'B', 'A']
 
#存储结果的数组,c[i+1, j+1] = LCS(S1[0...i], S2[0...j]),0<=i<m,0<=j<n
c = [[0 for col in range(len(S2) + 1)] for row in range(len(S1) + 1)]
#用于构造最优解,b[i][j]指向一个表项,这个表项对应于在计算c[i][j]时所选择的最优子问题的解
b = [[0 for col in range(len(S2))] for row in range(len(S1))]
 
#初始化c数组
for i in range(len(c)):     
    c[i][0] = 0
for j in range(len(c[0])):
    c[0][j] = 0
    
##初始化b数组
#for i in range(len(S1)):
#    b1 = []
#    for j in range(len(S2)):
#        b1.append(0)
#    b.append(b1) 
 
#使用动态规则计算S1和S2的最长子序列
#返回最长子序列的长度
def LCS(S1, S2):
    for i in range(len(S1)):
        for j in range(len(S2)):
            if S1[i] == S2[j]:
                c[i + 1][j + 1] = c[i][j] + 1
                b[i][j] = "↖"
            elif c[i][j + 1] >= c[i + 1][j]:
                c[i + 1][j + 1] = c[i][j + 1]
                b[i][j] = "↑"
            else:
                c[i + 1][j + 1] = c[i + 1][j]
                b[i][j] = "←"
    return c[len(S1)][len(S2)]
 
#根据表b构造出一个LCS 
def print_LCS(b, X, i, j):
    if i == -1 or j == -1:
        return 
    if b[i][j] == "↖" :
        print_LCS(b, X, i-1, j-1)
        print X[i]
    elif b[i][j] == "↑":
        print_LCS(b, X, i-1, j)
    else:
        print_LCS(b, X, i, j-1)
 
print(LCS(S1, S2))
print_LCS(b, S1, len(S1) - 1, len(S2) - 1)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • 公共子序列与公共子串不同在于子序列不要求连续。利用两个二维数组进行求解,c数组负责存值,求得子序列最大长度,即途中...
    icecrea阅读 3,762评论 0 1
  • 动态规划(Dynamic Programming) 本文包括: 动态规划定义 状态转移方程 动态规划算法步骤 最长...
    廖少少阅读 3,252评论 0 18
  • 问题描述: 求两个字符序列的公共最长子序列。 最长公共子串 在回到子序列问题之前,先来了解一下子串的问题。例如,H...
    我没有三颗心脏阅读 1,441评论 0 1
  • 我是日记星球的114号星宝宝,这是我的第69篇原创日记。 我一直都想开一家对贫困人群免费的养老院,一家医院。 20...
    书香天使阅读 243评论 0 2