• 【字符串匹配算法】KMP、哈希


    STL O(mn)

    C++中提供子串查询的函数可以使用std::string类的相关方法来实现。 

    1. find函数:可以查找一个子串在原字符串中的第一个出现位置。它返回子串的起始索引,如果找不到则返回std::string::npos
    2. substr函数:可以提取原字符串中的一个子串,根据起始位置和长度来确定子串的范围。
    3. compare函数:可以比较两个字符串是否相等或者大小关系
    1. #include
    2. const int N=1e5+10;
    3. signed main()
    4. {
    5. std::string s1="hello world";
    6. std::string s2="hello";
    7. //find函数
    8. if(s1.find(s2)!=std::string::npos)//如果是子串
    9. {
    10. std::cout<<"yes"<<'\n';
    11. }else{
    12. std::cout<<"no"<<'\n';
    13. }
    14. //substr提取子串
    15. std::string s3=s1.substr(0,5);
    16. std::cout<'\n';
    17. //比较字符串大小关系
    18. if(s1.compare(s3)==0) // 字符串相等
    19. {
    20. std::cout<<"equl"<<'\n';
    21. }else if(s1.compare(s3)<0){// str1小于str2
    22. std::cout<<"s1 is less than s3"<<'\n';
    23. }else{ // str1大于str2
    24. std::cout<<"s3 is less than s1"<<'\n';
    25. }
    26. return 0;
    27. }

     find函数的时间复杂度取决于字符串的长度和待查找的子串的长度。在C++标准库中,std::stringfind函数使用的是一种称为"Boyer-Moore-Horspool"算法的快速字符串搜索算法

    在最坏情况下,算法的时间复杂度为O(mn),其中n是字符串的长度,m是待查找的子串的长度。这种情况发生在待查找的子串中的每个字符都与字符串进行了比较,但最终没有匹配成功。

    时间复杂度是不如KMP的


    KMP算法 O(m+n)

    KMP算法是对暴力算法的优化

    在暴力算法中我们定义两个指针i,j从0开始,

            如果s[i]==x[j],则i++,j++

            否则j=0(将子串移到开头,重新比较)

    KMP算法则是在s[i]!=x[j]的情况下进行优化,如果不相等不将j移到0,而是根据预处理的结果来确定。

    比如:

    s  BBC ABCDAB ABCDABCDABDE

    x  ABCDABD

    比如到这一步时,x[j]!=s[i] 

    这是暴力做法:

     

    这是KMP算法: 

    我们利用了ABCDAB中 后面的AB等于前面AB这一信息。

    字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB"。我们需要学的就是如何利用这一信息。

    n e [ i ] = j 的定义是p [ 1 , j ] = p [ i - j + 1 , i ]

    对ne数组求解时,要牢抓定义

    ne【1】=0,因此i从2开始计算,j从0开始,记录前后缀相等的最大长度

    字符串匹配的KMP算法 - 阮一峰的网络日志 (ruanyifeng.com)

    如果p【i】==p【j+1】,那么j++

    否则j一直往前找,直到p【i】==p【j+1】

    最后p【i】==p【j+1】,ne【i】=j

    代码 

    1. #include
    2. using namespace std;
    3. const int N=1e6+10;
    4. char p[N],s[N];
    5. int m,n;
    6. int ne[N];
    7. signed main()
    8. {
    9. cin>>n>>p+1>>m>>s+1;
    10. for(int i=2,j=0;i<=n;i++)
    11. {
    12. while(j&&p[i]!=p[j+1]) j=ne[j];
    13. if(p[i]==p[j+1]) j++;
    14. ne[i]=j;
    15. }
    16. for(int i=1,j=0;i<=m;i++)
    17. {
    18. while(j&&s[i]!=p[j+1]) j=ne[j];
    19. if(s[i]==p[j+1]) j++;
    20. if(j==n)
    21. {
    22. std::cout<" ";
    23. j=ne[j];
    24. }
    25. }
    26. return 0;
    27. }

    字符串哈希

    AcWing 841. 字符串哈希 【公式助理解】 - AcWing

     

    1. #include
    2. typedef unsigned long long ULL;
    3. const int N=1e5+10,P=131;
    4. char str[N];
    5. int p[N],h[N];
    6. ULL get(int l,int r)
    7. {
    8. return h[r]-h[l-1]*p[r-l+1];
    9. }
    10. signed main()
    11. {
    12. int n,m;
    13. std::cin>>n>>m>>str+1;
    14. p[0]=1;
    15. for(int i=1;i<=n;i++)
    16. {
    17. p[i]=p[i-1]*P;
    18. h[i]=h[i-1]*P+str[i];
    19. }
    20. while(m--)
    21. {
    22. int l1,r1,l2,r2;
    23. std::cin>>l1>>r1>>l2>>r2;
    24. if(get(l1,r1)==get(l2,r2)) std::cout<<"Yes"<<'\n';
    25. else std::cout<<"No"<<'\n';
    26. }
    27. return 0;
    28. }

  • 相关阅读:
    重磅!2022年全球汽车零部件供应商百强发布
    关于eclipse导入项目出现红色叉或者红色感叹号的各种处理方法
    windows端口号占用
    SpringBoot电商项目实战Day2 堆(优先队列)
    Swagger使用
    Git(二)版本控制、发展历史、初始化配置、别名
    244:vue+openlayers 显示滚动效果的线段Line
    程序员的底层思维
    【笔试题】【day17】
    vpp hqos分析
  • 原文地址:https://blog.csdn.net/m0_74183164/article/details/133914327