分两种,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;
}