[leetcode 面试题 17.17] -- 多次搜索

  • 题目来源
  • 分析
  • KMP思路
    • 完整代码
  • 字典树
    • 完整代码

题目来源

https://leetcode-cn.com/problems/multi-search-lcci/

分析

题目就是让从一长串字符中,搜索最多1e5个字符串,找到所有字符串出现的位置。

第一种朴素的做法就是直接查找,但是不能暴力查找,因为暴力搜索时间复杂度是O(n * n),很容易超时。可以使用KMP算法,他的时间复杂度是O(n + m),加上这个题也就是O(n + m) * 1e5,也就是1e8左右,应该是可以的。

第二种方法就是利用字典树,先对所有的子串进行建树,因为子串都是小写字母,所以可以建26个以每个小写字母为根的树,树的每个节点都有最多26个孩子节点。需要注意的是,树的叶子节点一定是一个需要找的子串,但是也可能树的中间的一个节点也是子串,所以我们需要再建立一个额外的数组来保存每个子串出现的位置。
时间复杂度 建树是 O(1e8) + 搜索 O(1e6)也是可以完成的。

KMP思路

KMP算法就是一个跳跃式的寻找前缀的算法。
我们平常的暴力写法是这样的

这样的搜索复杂度是n * m 了,而KMP算法却可以让这个复杂度变成n + m,因为他们都有一个公共前缀aa,我们每次遍历基本上就可以说是线性的。

每一次我们发现对应位置的字符不相同的时候,就向前移动next数组,这个时候就有两种情况

  • 前面没有与这个前缀相同的字符,那么就从当前位置再重新查找
  • 前面有相同的字符,就直接从这个字符开始,向后匹配。

在这之前,我们需要维护我们的next数组,这样就可以方便我们遍历的时候更快的找到我们公共前缀

然后我们再遍历源字符串,从源字符串中查找匹配的情况。

完整代码

class Solution {public:vector<vector<int>> multiSearch(string big, vector<string>& smalls) {vector<vector<int> > ans;//依次搜索所有的子串for(auto& eoch : smalls)ans.push_back(kmp(big,eoch));return ans;}vector<int> kmp(string s,string p){vector<int> ret;int lens = s.size();int lenp = p.size();//如果有一个为空的字符串,说明匹配不到结果if(!lens || !lenp) return ret;vector<int> next(lenp,0);for(int i = 1, j = 0; i < lenp; i++){//确保j-1合法  当前位置不相等,就跳到上一个位置while(j && p[i] != p[j])j = next[j-1];if(p[i] == p[j])j++;next[i] = j;}for(int i = 0, j = 0; i < lens; i++){while(j && s[i] != p[j])j = next[j-1];if(s[i] == p[j])j++;//成功匹配if(j == lenp){ret.push_back(i-lenp+1);j = next[j-1];}}return ret;}
};

字典树


整个过程分为三步

  • 先把所有待匹配的字符串,依次以他们的首字符为根节点,然后构成一棵树,并在每一次遍历完成之后,统计叶子节点的下标。因为存在,caacaaa,这样的话第二次统计就覆盖了前一次的叶子节点。
  • 第二步就是搜索了,从源字符串的每一个位置开始,每一次都统计出以当前位置开始的待匹配字符串,把他们用一个hash表保存起来。
  • 遍历待匹配字符串,找到他们每一个字符串出现的位置数组。

完整代码

class Solution {public://字典树const static int N = 100010;int son[N][26];//字典树int idx;string key[N];vector<vector<int>> multiSearch(string big, vector<string>& smalls) {//生成字典树for(auto& eoch : smalls)insert(eoch);//查找所有子串出现的情况unordered_map<string,vector<int> > hash;for(int i = 0; i < big.size(); i++)search(big,i,hash);vector<vector<int> > ans;for(auto& eoch : smalls)ans.push_back(hash[eoch]);return ans;}void insert(string& s){int p = 0;for(int i = 0; i < s.size(); i++){int u = s[i] - 'a';//如果这个地方之前没有出现过这个字母的路径,就新加一个节点if(!son[p][u]) son[p][u] = ++idx;p = son[p][u];}//叶子节点记录这个字串的信息key[p] = s;}void search(string& s,int index,unordered_map<string,vector<int> >& hash){int p = 0;for(int i = index; i < s.size(); i++){int u = s[i] - 'a';if(!son[p][u]) return; //说明没有需要查找的子串p = son[p][u];//key[p] != ""   判断这条路径是不是叶子节点,是叶子节点就添加开始位置到图中if(key[p] != "") hash[key[p]].push_back(index);}}
};

[leetcode 面试题 17.17] -- 多次搜索,KMP与字典树相关推荐

  1. 【亡羊补牢】挑战数据结构与算法 第19期 LeetCode 212. 单词搜索 II(字典树,附上JS模板)

    仰望星空的人,不应该被嘲笑 题目描述 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单词必须按照字母顺序,通过相邻的单元格内的字母构成, ...

  2. [Leetcode][第336题][JAVA][回文对][暴力][HashSet][字典树]

    [问题描述][困难] [解答思路] 1. 暴力(超时) 时间复杂度:O(n 2 ×m),其中 n 是字符串的数量,m 是字符串的平均长度 空间复杂度:O(1) class Solution {publ ...

  3. leetcode 面试题198+17.6

    此题可用动态规划求解,原数组为b[],我们用一个二维数组a[][2]来表示当前是否预约到客人,a[][0]就表示当前没有接预约,a[0][1]则表示接到预约,分析一下,对于按摩师来说 如果当前接到预约 ...

  4. leetcode面试题 10.05. 稀疏数组搜索(二分法)

    稀疏数组搜索.有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置. 示例1: 输入: words = ["at", "", &q ...

  5. CodeForces - 1285D Dr. Evil Underscores(记忆化搜索+字典树)

    题目链接:点击查看 题目大意:给出n个数字,现在要求出一个X,使得X与n个数字单独异或之后的最大值,输出这个最大值的最小值 题目分析:最大值的最小值,差点就以为是字典树+二分了,因为没有单调性然后就无 ...

  6. 字典树/Trie/前缀树-LeetCode总结:720词典中最长的单词;127. 单词接龙;677. 键值映射;面试题 17.17. 多次搜索;648. 单词替换

    MyTrie结构体和相关操作函数 typedef struct MyTrie {bool is_word;vector<MyTrie*> next;MyTrie():is_word(fal ...

  7. leetcode 面试题 17.14. 最小K个数 大顶堆 小顶堆 快排

    leetcode 面试题 17.14. 最小K个数 [难度:中等] 设计一个算法,找出数组中最小的k个数.以任意顺序返回这k个数均可. 示例: 输入: arr = [1,3,5,7,2,4,6,8], ...

  8. LeetCode:17.17.多次搜索

    给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索.输出smalls中的字符串在big里出现的所有位置position ...

  9. 面试题 16.17. 连续数列

    面试题 16.17. 连续数列https://leetcode.cn/problems/contiguous-sequence-lcci/ 难度简单114 给定一个整数数组,找出总和最大的连续数列,并 ...

最新文章

  1. OSI七层 TCP/IP四层 TCP/IP协议栈: 不同的通信协议的大集合
  2. 不学51直接学stm32可以吗?学stm32需要哪些基础?
  3. java 弱引用 集合_java 弱引用集合类WeakHashMap
  4. 【C/C++】C语言复习笔记-17种小算法-解决实际问题
  5. 『数据中心』供配电与空调设计基础知识
  6. AntV中的饼状图重复渲染问题解决
  7. SQL SERVER7应用
  8. flutter英语怎么说_美国人天天说的英语:“你搞反了”英语怎么说?
  9. 【实践】汽车之家推荐系统排序算法迭代之路.pdf(附下载链接)
  10. 马斯克火箭 SpaceX-API、程序员优雅赚钱项目……GitHub 热点速览
  11. [深度学习] loss不下降的解决方法
  12. java解析md文件_md格式详解
  13. Egoist (罪恶王冠) | mmd动作+镜头下载
  14. IT培训分享:11种热门编程语言的主要用途
  15. linux Guest账户下如何更新默认的python版本
  16. 定位position-relative
  17. 计算机等级考试准考证打河南,2019年河南牧院计算机等级考试准考证打印时间...
  18. webotAI网页版上线啦!
  19. Number isFinite()方法
  20. js 字符串截取数组常用方法总结(前端)

热门文章

  1. 真是太有用了——整理央视《家有妙招》不看别后悔幺
  2. 什么是计算机用英语解释,计算机词汇英语解释
  3. 计算机木马犯罪类型,计算机木马病毒犯罪研究..doc
  4. python将一些朋友的姓名存储在一个列表中,访问该列表中的每个元素,从而将每个朋友的姓名都打印出来...
  5. 陳三甲网络笔记:赚钱路上,一些人生思考(连载四)
  6. Power BI销售业绩分析
  7. VSCODE 使用One Dark Pro并优化
  8. 2019年中国在线酒店预订行业发展分析报告
  9. 幼师计算机能力自我评价,幼师简历范文
  10. C语言打印hello world