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

本文介绍了一种用于快速查找大型文本中关键字的算法,通过预处理建立后缀数组并优化排序过程,显著提高了查询效率。特别关注于如何利用查询字符串长度较小的特点,减少排序时间复杂度,从而解决实际应用中常见的大文本搜索问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


原文链接:http://blog.youkuaiyun.com/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 plain copy
  1. #include<algorithm>  
  2. using namespace std;  
  3. vector<char*> prefix;  
  4. bool compare(char* s, char* q)  
  5. {  
  6.     if ( !s || !q )  
  7.         return !s;  
  8.     int n=10;  
  9.     while(n--&&*s!='\0'&&*q!='\0')  
  10.     {  
  11.         if( *s < *q )  
  12.             return true;  
  13.         else if ( *s > *q )  
  14.             return false;  
  15.         else  
  16.             s++,q++;  
  17.     }  
  18.     if ( n==0 )  
  19.         return true;  
  20.     else  
  21.         return *s=='\0';  
  22. }  
  23. int startWith(char* src,char* query);  
  24. // 预处理初始化  
  25. void initWithString(char *str) {  
  26.     if ( !str )  
  27.         return;  
  28.     while(*str!='\0')  
  29.         prefix.push_back(str++);  
  30.     sort(prefix.begin(),prefix.end(),compare);  
  31. }  
  32. // 如果query是str的字串,返回true,否则返回false  
  33. bool existSubString(char *query) {  
  34.     if ( !query || *query=='\0' )  
  35.         return true;  
  36.     int l =0,r=prefix.size()-1;  
  37.     while(l<=r)  
  38.     {  
  39.         int mid=l+((r-l)>>1);  
  40.         int cmp=startWith(prefix[mid],query);  
  41.         if ( cmp == 0 )  
  42.             return true;  
  43.         else if (cmp<0 )  
  44.             l=mid+1;  
  45.         else  
  46.             r=mid-1;  
  47.     }  
  48.     return false;  
  49. }  
  50. int startWith(char* src,char* query)  
  51. {  
  52.     if ( !src || !query)  
  53.     {  
  54.         if ( !query )  
  55.             return 0;  
  56.         else   
  57.             return -1;  
  58.     }  
  59.     while(*src!='\0' && *query!='\0')  
  60.     {  
  61.         if ( *src<*query)  
  62.             return -1;  
  63.         else if ( *src >*query )  
  64.             return 1;  
  65.         else  
  66.             src++,query++;  
  67.     }  
  68.     if ( *query=='\0' )  
  69.         return 0;  
  70.     else  
  71.         return -1;  
  72. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值