最长重复数组

最长重复数组,具体可以参考编程珠玑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循环依次比较每个字符串,找到最长重复子字符串

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>

  4. //找到两个字符串公共部分的长度
  5. int comlen(char *p, char *q)
  6. {    
  7.     int i = 0;
  8.     while (*&& (*p++ == *q++))
  9.     {
  10.         i++;
  11.     }
  12.     return i;
  13. }

  14. int main()
  15. { 
  16.     int i, j;
  17.     int maxi, maxj;
  18.     int currentlen, maxlen = -1;
  19.     char *str = "ask not what your country can do for you, but what you can do for your country";
  20.     int length = strlen(str);

  21.     for(= 0; i < length; i++)
  22.     {
  23.         for(= i + 1; j < length; j++)
  24.         {
  25.             currentlen = comlen(str + i, str + j);
  26.             if(currentlen > maxlen)
  27.             {
  28.                 maxlen = currentlen;
  29.                 maxi = i;//i标记了最长公共子串开始的位置
  30.                 maxj = j;
  31.             }
  32.         }
  33.     }

  34.     for(= 0; i < maxlen; i++)
  35.     {
  36.         printf("%c", str[maxi + i]);
  37.     }
  38.     printf("n");
  39.     return 0;
  40. }

方法二:采用后缀数组来处理该问题
    我们的程序最多处理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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值