后缀树求最长子字符串

问题描述:

给定一个文本文件作为输入,查找其中的最长子字符串。例如, ”Ask not what your country can do for you, but what you can do for your country"中的“ can do for you"就是最长子字符串。

 

解题过程:

这个问题最直接的解法就是变位词程序(《编程珠玑》2.4节)。如果将输入字符串存储在c[0..n-1]中,那么我们可能会使用类似下面的伪代码比较每个子串;

复制代码
maxlen = -1;

for i = [0, n]

    for j = (i, n)

        if (thislen = comlen(&c[i], &c[j])) > maxlen

            maxlen = thislen;

            maxi = i;

            maxj = j;
复制代码

comlen函数返回其两个参数字符串中共同部分的长度,从第一个字符开始比较:

复制代码
  int comlen(char* p, char* q)

  {

      int i = 0;

      while (*q && (*p++ == *q++))

      {

          i++;

      }

      return i;

  }
复制代码

该算法需要的时间复杂度为o(n^2)。可以用散列表搜索短语中的单词来实现提速,但是这里有另一个跟好的算法:

我们将使用“后缀数组”的简单简单结构。

复制代码
  #define MAXN 50000



      char c[MAXN];

      char* a[MAXN];

      char ch;

      int n = 0;

      while ((ch = getchar()) != EOF)

      {

          a[n] = &c[n];

          c[n++] = ch;

      }

      c[n] = 0;
复制代码

如果c中存储的是“banana”,该数组的后缀数组内容就是:

a[0] = "banana"

a[1] = "anana"

a[2] = "nana"

……

然后对其进行排序,可以使用qsort来进行,对排序完的数组只需要一边扫描,统计相邻单词共有子串的长度。

思路就是这样,完整的代码如下:

复制代码
  #include <stdio.h>

  #include <stdlib.h>

  #include <string.h>



  #define MAXN 50000



  int comlen(char* p, char* q)

  {

      int i = 0;

      while (*q && (*p++ == *q++))

      {

          i++;

      }

      return i;

  }



  int cstring_cmp(const void *a, const void *b)

  {

      const char **ia = (const char **)a;

      const char **ib = (const char **)b;

      return strcmp(*ia, *ib);

  }



  int main()

  {

      char c[MAXN];

      char* a[MAXN];

      char ch;

      int n = 0;

      while ((ch = getchar()) != EOF)

      {

          a[n] = &c[n];

          c[n++] = ch;

      }

      c[n] = 0;



      qsort(a, n, sizeof(char*), cstring_cmp);



      int maxlen = 0;

      int len = 0;

      int maxi = 0;

      for (int i = 0; i < n - 1; i++)

    {

          len = comlen(a[i], a[i + 1]);

          if (len > maxlen)

          {

              maxlen = len;

              maxi = i;

          }

      }



      printf("maxlen:%d\tmax string:\t", maxlen);

      char ch_tmp;

      for (int i = 0; i < maxlen; i++)

      {

          ch_tmp = *(a[maxi] + i);

          printf("%c", ch_tmp);

      }

      printf("\n");



      return 0;

  }
复制代码

你可能感兴趣的:(字符串)