一道2015阿里校招系统工程师笔试代码题

问题:给定一个query和一个text,均由小写字母组成,要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度。例如,query为"acbac",text为"acaccbabb",那么text中的"cba"为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3,请注意程序效率。


在线笔试时没做出来,后来做了一下:
#include<stdio.h>
#include<string.h>

#define MAXLEN 1024

int max_sub_len(char *s, char *p);
int kmp_max_sub_len(char *s, char *p);
void get_next(char *str, int next[]);

char text[] = "acaccbabb";
char query[] = "acbac";

int main()
{
	int length;
	length = kmp_max_sub_len(text, query);
	//length = max_sub_len(text, query);
	printf("%d\n", length);
	return 0;
}

int max_sub_len(char *s, char *p)
{
	int s_len = strlen(s);
	int p_len = strlen(p);
	int max = 0;

	int i, j, k;
	for (k = 0; k < p_len; k++) {
		i = 0;
		j = 0;
		while (i < s_len && j < p_len - k) {
			if (s[i] == p[j + k]) {
				i++;
				j++;
				max = (max < j) ? j : max;
			} else {
				i = i - j + 1;
				j = 0;
			}
		}
	}
	return max;
}


void get_next(char *str, int next[])
{
	int i, j;
        int length=strlen(str);

	i = 0;
        j=1;
	next[0] = 0;
        while(j<length){
            if(str[i]==str[j]){
                next[j]=next[j-1]+1;
                i++;
                j++;
            }else{
                next[j]=0;
                j++;
                i=0;
            }
        }

}
int kmp_max_sub_len(char *s, char *p)
{
	int s_len = strlen(s);
	int p_len = strlen(p);
	int max = 0;
        int next[MAXLEN];
        char *n;

	int i, j, k;
	for (k = 0; k < p_len; k++) {
		i = 0;
		j = 0;
                n=p+k;
                get_next(n,next);
		while (i < s_len && j < p_len - k) {
			if (s[i] == p[j + k]) {
				i++;
				j++;
				max = (max < j) ? j : max;
			} else {
				i = i + j - next[j]+1;
				j = 0;
			}
		}
	}
	return max;
}



其中max_sub_len为朴素模式匹配,若text长度为m,所查询的query长度为n,则复杂度为O(m* n  * n);
kmp_max_sub_len使用了kmp算法,复杂度为O((m+n) * n)).

这个题目由于搜索模式是可变的,不再是单纯的kmp算法了,增加了n!这部分的复杂度,不知道这里是否还可以优化。


关于kmp算法,有两篇很好的文章:
一个在这
另一个在这


附注:后来查了下,寻找最长公共字串,属于动态规划,上面的解法可能不好。以前没学习这个,以后再来改

你可能感兴趣的:(Algorithm,c)