最长重复数组,具体可以参考编程珠玑15章
给定一个文本文件作为输入,插在其中最长的重复子字符串。例如,“Ask not what your country can do for you, but what you can do for your country”中最长的重复字符串是“can do for you”,第二长的是“your country”。
方法一:双重for循环依次比较每个字符串,找到最长重复子字符串
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
-
- //找到两个字符串公共部分的长度
- int comlen(char *p, char *q)
- {
- int i = 0;
- while (*p && (*p++ == *q++))
- {
- i++;
- }
- return i;
- }
-
- int main()
- {
- int i, j;
- int maxi, maxj;
- int currentlen, maxlen = -1;
- char *str = "ask not what your country can do for you, but what you can do for your country";
- int length = strlen(str);
-
- for(i = 0; i < length; i++)
- {
- for(j = i + 1; j < length; j++)
- {
- currentlen = comlen(str + i, str + j);
- if(currentlen > maxlen)
- {
- maxlen = currentlen;
- maxi = i;//i标记了最长公共子串开始的位置
- maxj = j;
- }
- }
- }
-
- for(i = 0; i < maxlen; i++)
- {
- printf("%c", str[maxi + i]);
- }
- printf("n");
- return 0;
- }
方法二:采用后缀数组来处理该问题
我们的程序最多处理MAXN个字符,这些字符存储在数组c中。
#define MAXN 50000
char c[MAXN], *a[MAXN];
我们使用一个称为“后缀数组”的数据结构,这个结构是一个字符指针数组,记为a。读取输入时,我们对a进行初始化,使得每个元素指向输入字符串中的相应字符:
while(ch = getchar() != EOF)
{
a[n] = &c[n];
c[n] = ch;
}
c[n] = 0;
元素a[0]指向整个字符串,下一个元素指向从第二个字符开始的数组后缀,等等。对于输入字符串“banana”,该数组能够表示如下后缀:
char *a="banana"
a[0]=banana
a[1]=anana
a[2]=nana
a[3]=ana
a[4]=na
a[5]=a
如果某个长字符串在数组c中出现了两次,那么它将出现在两个不同的后缀中,因此我们队数组进行排序以寻找相同的后缀。“banana”数组排序为:
a[0]=a
a[1]=ana
a[2]=anana
a[3]=banana
a[4]=na
a[5]=nana
然后就可以扫描数组,通过比较相邻元素来找出最长的重复字符串。
该方法由于排序的存在,时间复杂度为O(nlogn)。
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
//只能比较字符串,两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇''为止。
int pstrcmp(const void *p, const void *q)
{
return strcmp(*(char **)p, *(char **)q);
}
int comlen(char *p, char *q)//返回两个参数共同部分的长度
{ int i = 0;
while (*p && (*p++ == *q++))
i++;
return i;
}
#define M 1
#define MAXN 5000000
char c[MAXN], *a[MAXN];
int main()
{
int i, ch, n = 0, maxi, maxlen = -1;
while ((ch = getchar()) != EOF) {
a[n] = &c[n];
c[n++] = ch;
}
c[n] = 0;
qsort(a, n, sizeof(char *), pstrcmp);//快速排序
for (i = 0; i <n-M; i++)
{
if (comlen(a[i], a[i+M]) > maxlen) //比较相邻字符串相同个数
{
maxlen = comlen(a[i], a[i+M]);
maxi = i;
}
}
printf("%.*s\n", maxlen, a[maxi]);
return 0;
}