寻找最长公共子序列的分段错误

时间:2014-12-26 13:40:41

标签: c string longest-substring

问题陈述:给定两个相等长度的字符串a和b,可以构造的最长字符串(S)是什么,使得S是a和b的子节点。字符串x被称为字符串y的子节点,如果x可以通过从y中删除0个或多个字符来形成(即,找到最长的公共子序列)。

输入:两个字符串a和b,换行符分隔它们。

约束:所有字符都是大写的,位于ASCII值65-90之间。字符串a和b的最大长度为5000。

输出格式:字符串S的长度。

我的问题是我在一个测试案例中遇到了分段错误。 SOMEOE PLZ告诉我为什么?

这是我在C代码中的代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int max(int a, int b)
{

    return (a>b)?a:b;

}

int lcs(char *X, char *Y, int x, int y)
{

    int L[x+1][y+1];
    int i,j;

    for(i=0 ; i<=x ; i++)
    {
        for(j=0 ; j<=y ; j++)
        {
            if(i==0 || j==0)
              L[i][j] = 0;

           else if(X[i-1] == Y[j-1]) 
           {
              L[i][j] = 1 + L[i-1][j-1];
           }
          else
              L[i][j] = max(L[i-1][j],L[i][j-1]);

        }
    }
   return L[x][y];

}

int main() {

    char a[5000],b[5000];
    scanf("%s",a);
    scanf("%s",b);

    int lenA, lenB;

    lenA = strlen(a);
    lenB = strlen(b);

    printf("%d",lcs(a,b,lenA,lenB));   

    return 0;
}

1 个答案:

答案 0 :(得分:3)

我认为有三个可能的原因:

  1. 您的输入太大了。 scanf()不会检测到,但您可以指定要读取的最大字符串长度:

    的scanf(&#34;%4999s&#34;,α);

  2. 您尝试读取一个包含5000个字符的字符串,并将终止0的字符串读入5000个字符的数组中。这意味着终止0将覆盖某些任意内存,或者可能被下一次调用scanf覆盖。因此,只需将数组定义为大1字节。可以肯定的是,将它们定义为大2个字节,(a [5002],b [5002]),允许扫描5001个字符,检查扫描长度并抱怨它是否为5001.听起来很偏执,但显然出现了问题,因此你的代码应该准备好发现错误。

  3. L [x + 1] [y + 1]可能会导致相当大的数组。想象一下,你扫描两个5000字节的字符串,终止0会丢失,因为你的数组太短,而strlen会导致5012和10012.在这种情况下,你想在堆栈上分配200 MB。这非常多,可能会失败。即使您很幸运,并且您的字符串已正确终止,您仍可能需要100 MB的堆栈。这不是堆栈的工作方式。

  4. 顺便说一下 - 你正在实现Levenstein算法的变体 - Levenstein测量两个字符串之间的差异,同时测量公共部分,这只是同一个问题的另一个视图。你知道它可以在没有5001x5001矩阵的情况下实现吗?它足以在堆栈上有3x5001整数。为了计算结果矩阵的下一行,您只需要前两行,这意味着它足以在堆栈上保留3行矩阵。而这3行将适合。