[各种面试题] 字符串匹配查询
2015-10-08 09:22
393 查看
原文链接:http://blog.csdn.net/a83610312/article/details/11797911
传闻是FB 2012的题,真不是盖的啊。
有一个长度为n的字符串str,有非常多的关键字query(长度不超过10),需要判断每个关键字是否是str的子串。
注意:query是动态的输入进行查询的,预先并不知道所有的query。
请实现2个函数
有一个很重要的点是注意从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;
}
传闻是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;
}
相关文章推荐
- 作为程序员最应该投资的是这十件事
- 作为程序员最应该投资的是这十件事
- 100个iOS开发面试题汇总
- 100个iOS开发面试题汇总
- 我们对技术的依赖有多强?程序员为何关注它?—兄弟连IT教育
- 大学生面试成功的十大法宝
- 面试中最易被“秒杀”的十种表现
- 面试中最易被“秒杀”的十种表现
- 大学生面试成功的十大法宝
- [笔试题目] 简单总结笔试和面试中的海量数据问题
- 程序员不成熟的若干个特征
- 黑马程序员——IO概述之字节流和流对象缓冲技术
- 程序员装B指南
- [观点] 真正的程序员,请你站出来
- 技术总监谈好的程序员如何写代码
- 一篇关于程序员性格的文章 …
- 一篇关于程序员性格的文章(…
- 我在雅虎获得的 8 个最好的职业建议
- 你适不适合做程序员?
- 程序员加班到底在加什么?