当前位置:   article > 正文

字符串匹配算法(leetcode)_字符串匹配算法leetcode

字符串匹配算法leetcode

总结

  • 注意边界
  • 注意空串

一. 基本题目

leetcode 28 easy

1. BF算法(暴力匹配)

  1. class Solution {
  2. public:
  3. int strStr(string haystack, string needle) {
  4. // 0.异常处理
  5. if (0 == needle.size()) return 0;
  6. // 1.初始化准备
  7. int m = haystack.size();
  8. int n = needle.size();
  9. // 2.暴力匹配,[0, m-n]
  10. for (int i=0; i<=m-n; ++i) {
  11. int j = 0;
  12. // 开始匹配
  13. for (; j<n; ++j) {
  14. if (needle[j] != haystack[i+j]) break;
  15. }
  16. if (j == n) return i;
  17. }
  18. return -1;
  19. }
  20. };

时间复杂度O(n*m),空间复杂度O(1) 

2. RK算法

2.1 没有哈希冲突的方法

这会使得哈希值比较大,可能出现溢出情况

  1. class Solution {
  2. public:
  3. int strStr(string haystack, string needle) {
  4. // 0.异常处理
  5. if (0 == needle.size()) return 0;
  6. // 1.准备工作
  7. int m = haystack.size();
  8. int n = needle.size();
  9. // 1.1 26^0~26^(n-1)计算存储
  10. vector<long> powers(n);
  11. powers[0] = 1;
  12. for (int i=1; i<n; ++i) {
  13. powers[i] = powers[i-1] * 26;
  14. }
  15. // 1.2 主串哈希值计算,前后字符串有重叠部分,可以利用这个减少计算量
  16. unordered_map<long, vector<int>> mp; //hash_value -> start_position,拉链法解决哈希冲突
  17. // 1.2.1 首个子串哈希值计算
  18. long long hash = 0;
  19. for (int i=0; i<n; ++i) {
  20. hash += (haystack[i] - 'a') * powers[n-i-1];
  21. }
  22. mp[hash].push_back(0);
  23. // 1.2.2 [1, m-n)范围计算
  24. for (int i=1; i<=m-n; ++i) {
  25. hash = (hash - powers[n-1] * (haystack[i-1] - 'a')) * 26 + (haystack[i+n-1] - 'a');
  26. mp[hash].push_back(i);
  27. }
  28. // 2.正式处理
  29. // 2.1 计算needle哈希值
  30. hash = 0;
  31. for (int i=0; i<n; ++i) {
  32. hash += (needle[i] - 'a') * powers[n-i-1];
  33. }
  34. // 3.返回结果
  35. if (mp.find(hash) == mp.end()) return -1; //找不到
  36. return mp[hash][0]; //返回第一个
  37. }
  38. };

由于生成哈希值的方式,是唯一的,但是太大了,该代码会产生整数溢出的问题,时间复杂度生成哈希表的时间复杂度是O(m+n),匹配子串复杂度似是O(1),空间复杂度O(m+n) 

2.2 有哈希冲突的方法

降低生成哈希值的最大值,比如用字符串的每一个字符从编码相加作为哈希值,虽然会出现比较多的哈希冲突,但是可以避免整数溢出问题,出现哈希冲突就在检查一遍,也就是对哈希值相等的情况再去判断即可

  1. class Solution {
  2. public:
  3. int strStr(string haystack, string needle) {
  4. // 1.异常处理
  5. if (needle.size() == 0) return 0;
  6. // 2.准备工作,主要是生成主串中所有子串长度的字符串的哈希值
  7. int m = haystack.size();
  8. int n = needle.size();
  9. unordered_map<int, vector<int>> mp; //拉链法解决冲突
  10. // 2.1 首个哈希值计算
  11. int hash = 0;
  12. for (int i=0; i<n; ++i) {
  13. hash += (haystack[i] - 'a');
  14. }
  15. mp[hash].push_back(0);
  16. // 2.2 剩余[1, m-n]个子串哈希值计算,利用前后字符串的重复部分可以减少计算
  17. for (int i=1; i<=m-n; ++i) {
  18. hash = hash - (haystack[i-1] - 'a') + (haystack[n+i-1] - 'a');
  19. mp[hash].push_back(i);
  20. }
  21. // 3.匹配子串,注意哈希匹配了还是要检查一遍,因为存放不同的字符串对于相同哈希值的情况
  22. // 3.1 计算needle哈希值
  23. hash = 0;
  24. for (int i=0; i<n; ++i) {
  25. hash += (needle[i] - 'a');
  26. }
  27. // 3.2 开始匹配
  28. if (mp.find(hash) == mp.end()) return -1;
  29. // 检查每个结果
  30. for (auto &i : mp[hash]) {
  31. int j = 0;
  32. for (; j<n; ++j) {
  33. if (needle[j] != haystack[i+j]) break;
  34. }
  35. if (j == n) return i; //匹配
  36. }
  37. return -1; //虽然哈希值相同,但是全都不匹配
  38. }
  39. };

 时间复杂度O(n+m),空间复杂度O(n*最大冲突个数)

3. BM算法

4. KMP算法

KMP实现与分析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/50734
推荐阅读
相关标签
  

闽ICP备14008679号