首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

怎么找出两个字符串中最长的相同子串

2012-10-12 
如何找出两个字符串中最长的相同子串?写压缩算法,用的LZSS算法。但遇到如题这个问题的时候就卡着了,怎么办

如何找出两个字符串中最长的相同子串?
写压缩算法,用的LZSS算法。但遇到如题这个问题的时候就卡着了,怎么办呢?
在网上看到有个LCS算法,但并不适用于上面的算法啊,因为字符串buffer有8K!
现在我用的哈希表,但又出现一个问题:得到了匹配串,但哈希表的更新又很麻烦---要改变每个表值所对应字符串的地址.(不知道我这样说能不能理解)

哪位有办法啊?急啊....

[解决办法]
字符串1: bcgghadcced

字符串2: aggcadcbhe

最长共同子字符串: adc

算法思想:建立一个二维矩阵,二维矩阵的大小分别是这两个字符串的长度,然后对二位矩阵进行赋值,赋值原则是这样的,将其中一个字符串的每一个字母与另一个字符串中的每一个字母进行比较,如果字符相同,则赋值为1,否则赋值为0,对矩阵赋值后,从矩阵的右上角开始,寻找斜线方向上所有数字和最大的那一条线,此时连续的几个1就标志了最大的子字符串。 矩阵示意图如下:

b c g g h a d c c e d

a 0 0 0 0 0 1 0 0 0 0 0

g 0 0 1 1 0 0 0 0 0 0 0

g 0 0 1 1 0 0 0 0 0 0 0 

c 0 1 0 0 0 0 0 1 1 0 0

a 0 0 0 0 0 1 0 0 0 0 0

d 0 0 0 0 0 0 1 0 0 0 0

c 0 1 0 0 0 0 0 1 0 0 0 

b 1 0 0 0 0 0 0 0 0 0 0

h 0 0 0 0 1 0 0 0 0 0 0

e 0 0 0 0 0 0 0 0 0 1 0

部分代码如下:

 // comparsion
for(int n = 0; n< la; n++)
for(int m = 0; m< lb ; m++)
{
if(a[n] == b[m])
{
if(m == 0 || n == 0) 
ab[n][m] = 1;
else
ab[n][m] = ab[n-1][m-1] +1;
}
else 
ab[n][m] = 0;
}
// result for comparsion 
for(i =0;i {
for(j =0 ;j {
printf("%d ",ab[i][j]);
}
printf("\n");
}
// get common result string;
int max = 0,index=0;
int maxa[MAXCH]; 
memset(maxa,0,MAXCH);
for(i = 0; i {
max = 0;
for(j = 0;j {
if(ab[i][j]>max)
{
maxa[i] = ab[i][j],
max = ab[i][j];
}

}
}
for(i=0;i printf("%d \n",maxa[i]);
max = 0;
for(i = 0;i {
if(maxa[i] > max)
{
max = maxa[i];
index = i;
}
}

获得最长子字符串:

for(i=0;i {
printf("%c",a[index-max+1+i]);
}

[解决办法]

C/C++ code
char* GetSubstring(char* strSource) { char* strSubstring; //用于保存得到的子串,大小在找到最大子串后再确定,作为返回值 int nLen; //源字符串长度 int nCurPos; //当前统计字符串的头指针位置(相对于原字符串第一个字符的位置) int nCurCount; //当前统计字符串的长度(有相同字符组成的子字符串) int nPos; //当前最长的子串的头指针位置 int nCount; //当前最长的子串的长度 nLen = strlen(strSource); //初始化变量 nCount = 1; nPos = 0; nCurCount = 1; nCurPos = 0; //遍历整个字符串 for(i = 1; i < nLen; i++) { if(strSource[i] == strSource[nCurPos])//如果当前字符与子串的字符相同,子串长度增1 nCurCount++; else //如果不相同,开始统计新的子串 { if(nCurCount > nCount)//如果当前子串比原先最长的子串长,把当前子串信息(起始位置 + 长度)保留下来 { nCount = nCurCount; nPos = nCurPos; } //长度复值为1,新串的开始位置为i nCurCount = 1; nCurPos = i; } } //为返回的子串分配空间(长度为nCount,由于要包括字符串结束符\0,故大小要加1) strSubstring = (char*)malloc(nCount + 1); //复制子串(用其他函数也可以) for(i = 0; i < nCount; i++) strSubstring[i] = strSource[nPos + i]; strSubstring[nCount] = '\0'; return strSubstring; } //不太明白你的“输出”究竟是什么意思,只好给段示意性代码 main() { //输入一个字符串strSource char* strSubstring = GetSubstring(strSource); printf("最长子串为:%s\n长度为:%d",strSubstring,strlen(strSubstring)); //释放strSubstring free(strSubstring); }
[解决办法]
lingyin55的算法应该是对的。
可以改进的地方主要是那个二维数组。8k * 8k * sizeof(int) 是有点大了。其实只要保留最近的两行就足够了。
[解决办法]
最大子串,要高效实现还蛮有难度的。
http://topic.csdn.net/u/20071206/20/8bb17656-f52f-4ad2-879e-16e25b864fcf.html

可以参考下这个DP解。
------解决方案--------------------


C/C++ code
#define   BUFFSIZE   1024         void   main()     {             char   sz1[BUFFSIZE]   =   {"abractyeyt"};             char   sz2[BUFFSIZE]   =   {"dgdsaeactyey"};             char   sz3[BUFFSIZE];             char   sz4[BUFFSIZE];                 char   ch1,   ch2;             int   i   =   0;             int   j   =   0;             int   k   =   0;                 for   (i   =   0;   i   <   strlen(sz1);   i++)               {                     ch1   =   sz1[i];                     for   (j   =   0;   j   <   strlen(sz2);   j++)                     {                             if   (ch1   =   sz2[j])                               {                                     for   (k   =   0;   (k+i)   <   strlen(sz1)   &&   (k+j)   <   strlen(sz2);   k++)                                     {                                             if   (sz1[i+k]   ==   sz2[j+k])   {                                                     sz3[k]   =   sz1[i+k];                                             }                                             else   {                                                     break;                                             }                                     }                             }                             if   (strlen(sz3)   >   strlen(sz4))                             {                                     strcpy(sz4,   sz3);                             }                             strcpy(sz3,   "");                     }             }                         printf("sz3   is   %s\n",   sz3);             printf("sz4   is   %s\n",   sz4);
[解决办法]
lingyin55的算法中,要求出ab[n][m],只需要知道ab[n-1][m-1]。
如果是用滑动的做法,那么只要m已知,就可以让n滑动。
对于任意的第n行,只需保留上一行就可以了。空间上应该是可行的做法。
[解决办法]
1.将两个字符串相连,其中,连接部分放一个在两个字符串中都没有出现的字符.
2.构造这个串的后缀数组.
3.求后缀的最长公共前缀.

其中用倍增法构造后缀数组:O(nlogn),用DC3算法是O(n)
求后缀的最长公共前缀:O(n)
时间复杂度可以做到O(n)
你把8k换成8万都没有问题.
空间复杂度是O(n).

更多情况参考:
许智磊2004.pdf
的文章.

IOI2004国家集训队论文 许智磊
第 1 页 共11页
后 缀 数 组
安徽省芜湖市第一中学 许智磊
【摘要】
本文介绍后缀数组的基本概念、方法以及应用。
首先介绍O(nlogn)复杂度构造后缀数组的倍增算法,接着介绍了配合后缀
数组的最长公共前缀 LCP(Longest Common Prefix)的计算方法,并给出一个
线性时间内计算height 数组(记录跨度为1 的LCP 值的数组)的算法。为了让
读者对如何运用后缀数组有一个感性认识,还介绍了两个应用后缀数组的例子:
多模式串的模式匹配(给出每次匹配O(m+logn)时间复杂度的算法)以及求最
长回文子串(给出O(nlogn)时间复杂度的算法)。最后对后缀数组和后缀树作了
一番比较。
【关键字】
字符串 后缀 k-前缀比较关系
后缀数组 名次数组 后缀树 倍增算法 基数排序
最长公共前缀 RMQ问题 模式匹配 回文串 最长回文子串

热点排行
Bad Request.