• 两种简单的字符串匹配算法


    在机试笔记4中的统计子字符串个数题目中,使用了一种时间复杂度为O(n*m)的字符串匹配算法,他也叫暴力匹配算法或者BF算法。在实际的开发中,它却是一个比较常用的字符串匹配算法。原因有以下几点:

    第一,实际的软件开发中,大部分情况下,模式串和主串的长度都不会太长。而且每次模式串与主串中的子串匹配的时候,当中途遇到不能匹配的字符的时候,就可以就停止了,不需要把 m 个字符都比对一下。所以,尽管理论上的最坏情况时间复杂度是 O(n*m),但是,统计意义上,大部分情况下,算法执行效率要比这个高很多。

    第二,朴素字符串匹配算法思想简单,代码实现也非常简单。简单意味着不容易出错,如果有 bug 也容易暴露和修复。在工程中,在满足性能要求的前提下,简单是首选。这也是我们常说的KISS(Keep it Simple and Stupid)设计原则。

    所以,在实际的软件开发中,绝大部分情况下,朴素的字符串匹配算法就够用了。

    一个长为n的主串中去查找长为m的模式串,最多要对比n-m+1个子串与模式串。

    另一个字符串匹配算法叫RK算法,它的算法思想是:

    我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了。这里当然会有哈希冲突的可能。

    哈希函数的设计:

        假设字符串只有小写字母,可以把每个子字符串当成一个26进制数,哈希函数就是把这个26进制数转成10进制数。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    double my_hash(string str)
    {
        double sum = 0;
        int j=0;
        for(int i=str.size();i>=0;i--){
            double index = pow(26,j);
            sum+=(str[i]-'a')*index;
            j++;
        }
        return sum;
    }
    
    int main()
    {
        int n;
        int m;
        string  a,b;
        cin >> n>> m;
        getchar();
        getline(cin,a);
        getline(cin,b);
        double* arr = new double[n-m+1];
        for(int i=0;i<n-m+1;i++){
            string c = a.substr(i,m);
            arr[i]=my_hash(c);
        }
        double v = my_hash(b);
        int sum = 0;
        for(int i=0;i<n-m+1;i++){
            if(arr[i]==v)
                sum++;
        }
        cout << sum<< endl;
        return 0;
    }

     当然这个代码还有需要优化的地方,一是计算指数可以变成查表的方式,二是求其十进制时前后两个子串的计算是有交集的。

  • 相关阅读:
    WEB网站类型系统中使用的OFFICE控件
    【架构】原型设计工具一览
    【云计算】mesos+marathon 服务发现、负载均衡、监控告警方案
    【自动部署该怎么做?】
    【OpenStack 虚拟机初始化user-data & Cloud-init】
    【数据可视化 参考资料】
    【RabbitMQ 参考资料】
    【CloudFoundry】架构、设计参考
    【OpenStack项目管理-CPU/内存/存储/网络 配额管理】
    【前端自动化构建 grunt、gulp、webpack】
  • 原文地址:https://www.cnblogs.com/Sunqingyi/p/12638555.html
Copyright © 2020-2023  润新知