最长公共子序列

31 篇文章 1 订阅

分两种,LCS(Longest Common Subsequences)不连续也可
和LSS(最长公共子串)必须连续

先说LCS

最容易想到的是穷举,然而最容易想到的肯定时空复杂度不行。
设序列X={x1,x2,….xm}和Y= {y1,y2…,yn}的一个最长公共子序列为Z={z1,z2,…zk},则
(1) 若xm=yn ,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列。
(2)若xm≠yn,且zk≠xm,则z是Xm-1和Y的最长公共子序列。
(3)若xm≠yn且zk≠yn,则Z是X和Yn-1的最长公共子序列。

由最长公共子序列问题的最优子结构性质可知,要找出X={x1,x2,….xm}和Y={y1,y2…yn}的最长公共子序列,可以按照以下方式递归的进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得到X和Y的一个最长公共子序列,当xm≠yn时,必须接两个字问题,也就是要找出Xm-1和Yn的一个最长公共子序列已经Xm和Yn-1的一个最长公共子序列。并求两个子问题公共子序列最长的。
1.求长度

#!/usr/bin/env python
# -*- coding: utf-8 -*-


def lcs(a, b):
    if 0 == len(a) or 0 == len(b):
        return 0
    else:
        if a[0] == b[0]:
            return lcs(a[1:], b[1:]) + 1
        else:
            return lmax(lcs(a[1:], b), lcs(a, b[1:]))


def lmax(a, b):
    if a >= b:
        return a
    else:
        return b

if __name__ == '__main__':
    s1 = raw_input()
    s2 = raw_input()
    # s1 = "acca"
    # s2 = "cbbc"
    l1 = list(s1)
    l2 = list(s2)
    print lcs(l1, l2)

2.如果想要输出这个子序列只需稍加修改

def lcs(a, b):
    if 0 == len(a) or 0 == len(b):
        return ""
    else:
        if a[0] == b[0]:
            return a[0] + lcs(a[1:], b[1:])
        else:
            return lmax(lcs(a[1:], b), lcs(a, b[1:]))


def lmax(a, b):
    if len(a) >= len(b):
        return a
    else:
        return b

if __name__ == '__main__':
    # s1 = raw_input()
    # s2 = raw_input()
    s1 = "abcicba"
    s2 = "abdkscab"
    l1 = list(s1)
    l2 = list(s2)
    print lcs(l1, l2)

再说LSS

基本的套路是将X的每个子串与Y的每个子串做对比,求出最长公共子串

def getcomlen(a, b):
    clen = 0
    while a and b:
        if a[0] == b[0]:
            clen += 1
            a = a[1:]
            b = b[1:]
        else:
            break
    return clen


def lss_base(a, b):
    max_len = 0
    c_index = 0
    for x in xrange(0, len(a)):
        for y in xrange(0, len(b)):
            c_temp = getcomlen(a[x:len(a)], b[y:len(b)])
            if c_temp > max_len:
                max_len = c_temp
                c_index = x

    print max_len
    print a[c_index:c_index + max_len]
if __name__ == '__main__':
    # s1 = raw_input()
    # s2 = raw_input()
    s1 = "asdfas"
    s2 = "werasDfaswer"
    s1 = s1.lower()
    s2 = s2.lower()
    l1 = list(s1)
    l2 = list(s2)
    lss_base(s1, s2)

将分别打印出长度和子串

同样的方法改成C++实现,代码将会长很多

#define MAX 1024

#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;

void mytolower(char* strSrc)
{
    while ( *strSrc != '\0')
    {
        if ( *strSrc >= 'A' && *strSrc <= 'Z')
        {
            *strSrc = *strSrc +32;
        }
        strSrc ++;
    }
}

int GetCurCommonStrLength(char* strFirst,char* strSecond)
{
    int nLength = 0;
    while ( *strFirst == *strSecond)
    {
        if (*strFirst == 0 || *strSecond  == 0)
        {
            break;
        }
        else
        {
            nLength++;
            strFirst ++;
            strSecond++;
        }
    }
    return nLength;
}

int GetCommonStrLength(char* pStrFirst,char* pStrSecond)
{
    if ( NULL == pStrFirst || NULL == pStrSecond)
    {
        return 0;
    }

    if ( pStrFirst == "" || pStrSecond == "")
    {
        return 0;
    }

    char strFirsttemp[MAX] = {0};
    char strSecondtemp[MAX] = {0};

    strcpy(strFirsttemp,pStrFirst);
    strcpy(strSecondtemp,pStrSecond);

    mytolower(strFirsttemp);
    mytolower(strSecondtemp);

    char* strFirst = strFirsttemp;
    char* strSecond = strSecondtemp;

    int nCommonLength = 0;
    while ( *strFirst != '\0')
    {
        while ( *strSecond != '\0')
        {
            if ( *strFirst == *strSecond)
            {
                int nTempCommon = GetCurCommonStrLength(strFirst,strSecond);
                if ( nTempCommon > nCommonLength)
                {
                    nCommonLength = nTempCommon;
                }
            }
            strSecond++;
        }
        strSecond = strSecondtemp;
        strFirst++;
    }
    return nCommonLength;
}

int main()
{
    char str1[MAX] = {0};
    char str2[MAX] = {0};
    scanf("%s", str1);
    scanf("%s", str2);
    cout << GetCommonStrLength(str1,str2) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值