您的位置:首页 > 职场人生

[各种面试题] 字符串匹配查询

2015-10-08 09:22 393 查看
原文链接:http://blog.csdn.net/a83610312/article/details/11797911

传闻是FB 2012的题,真不是盖的啊。

有一个长度为n的字符串str,有非常多的关键字query(长度不超过10),需要判断每个关键字是否是str的子串。

注意:query是动态的输入进行查询的,预先并不知道所有的query。

请实现2个函数
initWithString(str)
existSubString(query)
。我们会首先调用一次
initWithString(str)
,你可以在这个函数中做一些预处理操作。然后对于每一个query,函数
existSubString(query)
需要返回这个query是否为str的子串。

有一个很重要的点是注意从query长度不超过10能挖掘出什么来。

预处理肯定是要建立后缀数组的了,然后排序,之后就可以拿query串到排序数组里去找是否是某个串的前缀,如果是的话就返回true了。

这样做是可解的了,主要是注意sort时候要给一个比较函数,不然就拿char*的地址来比较了。

但是很容易发现源串的长度会非常大,比如1000000,这样建立后缀数组后,排序的时间会非常的长,我们需要从query串长度很小这里来优化一下这个排序,既然query与后缀数组中的串最多也就比较10次,那么后缀数组中的两个后缀大于10的长度之后的字符的关系其实是没有意义的,所以排序的时候,比较两个串只用看前10个的关系,这样排序的效率就提升了很多,也就不会超时了。

[cpp] view
plaincopy

#include<algorithm>

using namespace std;

vector<char*> prefix;

bool compare(char* s, char* q)

{

if ( !s || !q )

return !s;

int n=10;

while(n--&&*s!='\0'&&*q!='\0')

{

if( *s < *q )

return true;

else if ( *s > *q )

return false;

else

s++,q++;

}

if ( n==0 )

return true;

else

return *s=='\0';

}

int startWith(char* src,char* query);

// 预处理初始化

void initWithString(char *str) {

if ( !str )

return;

while(*str!='\0')

prefix.push_back(str++);

sort(prefix.begin(),prefix.end(),compare);

}

// 如果query是str的字串,返回true,否则返回false

bool existSubString(char *query) {

if ( !query || *query=='\0' )

return true;

int l =0,r=prefix.size()-1;

while(l<=r)

{

int mid=l+((r-l)>>1);

int cmp=startWith(prefix[mid],query);

if ( cmp == 0 )

return true;

else if (cmp<0 )

l=mid+1;

else

r=mid-1;

}

return false;

}

int startWith(char* src,char* query)

{

if ( !src || !query)

{

if ( !query )

return 0;

else

return -1;

}

while(*src!='\0' && *query!='\0')

{

if ( *src<*query)

return -1;

else if ( *src >*query )

return 1;

else

src++,query++;

}

if ( *query=='\0' )

return 0;

else

return -1;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: