字符串匹配算法(leetcode)

27 篇文章 0 订阅

总结

  • 注意边界
  • 注意空串

一. 基本题目

leetcode 28 easy

1. BF算法(暴力匹配)

class Solution {
public:
    int strStr(string haystack, string needle) {
        // 0.异常处理
        if (0 == needle.size()) return 0;
        // 1.初始化准备
        int m = haystack.size();
        int n = needle.size();
        // 2.暴力匹配,[0, m-n]
        for (int i=0; i<=m-n; ++i) {
            int j = 0;
            // 开始匹配
            for (; j<n; ++j) {
                if (needle[j] != haystack[i+j]) break;
            }
            if (j == n) return i;
        }
        return -1;
    }
};

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

2. RK算法

2.1 没有哈希冲突的方法

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

class Solution {
public:
    int strStr(string haystack, string needle) {
        // 0.异常处理
        if (0 == needle.size()) return 0;
        // 1.准备工作
        int m = haystack.size();
        int n = needle.size();
        // 1.1 26^0~26^(n-1)计算存储
        vector<long> powers(n);
        powers[0] = 1;
        for (int i=1; i<n; ++i) {
            powers[i] = powers[i-1] * 26;
        }
        // 1.2 主串哈希值计算,前后字符串有重叠部分,可以利用这个减少计算量
        unordered_map<long, vector<int>> mp; //hash_value -> start_position,拉链法解决哈希冲突
        // 1.2.1 首个子串哈希值计算
        long long hash = 0;
        for (int i=0; i<n; ++i) {
            hash += (haystack[i] - 'a') * powers[n-i-1];
        }
        mp[hash].push_back(0);

        // 1.2.2 [1, m-n)范围计算
        for (int i=1; i<=m-n; ++i) {
            hash = (hash - powers[n-1] * (haystack[i-1] - 'a')) * 26 + (haystack[i+n-1] - 'a');
            mp[hash].push_back(i);
        }

        // 2.正式处理
        // 2.1 计算needle哈希值
        hash = 0;
        for (int i=0; i<n; ++i) {
            hash += (needle[i] - 'a') * powers[n-i-1];
        }

        // 3.返回结果
        if (mp.find(hash) == mp.end()) return -1; //找不到
        return mp[hash][0]; //返回第一个
    }
};

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

2.2 有哈希冲突的方法

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

class Solution {
public:
    int strStr(string haystack, string needle) {
        // 1.异常处理
        if (needle.size() == 0) return 0;
        // 2.准备工作,主要是生成主串中所有子串长度的字符串的哈希值
        int m = haystack.size();
        int n = needle.size();

        unordered_map<int, vector<int>> mp; //拉链法解决冲突
        // 2.1 首个哈希值计算
        int hash = 0;
        for (int i=0; i<n; ++i) {
             hash += (haystack[i] - 'a');
        }
        mp[hash].push_back(0);

        // 2.2 剩余[1, m-n]个子串哈希值计算,利用前后字符串的重复部分可以减少计算
        for (int i=1; i<=m-n; ++i) {
            hash = hash - (haystack[i-1] - 'a') + (haystack[n+i-1] - 'a');
            mp[hash].push_back(i);
        }

        // 3.匹配子串,注意哈希匹配了还是要检查一遍,因为存放不同的字符串对于相同哈希值的情况
        // 3.1 计算needle哈希值
        hash = 0;
        for (int i=0; i<n; ++i) {
            hash += (needle[i] - 'a');
        }
        // 3.2 开始匹配
        if (mp.find(hash) == mp.end()) return -1;
        // 检查每个结果
        for (auto &i : mp[hash]) {
            int j = 0;
            for (; j<n; ++j) {
                if (needle[j] != haystack[i+j]) break;
            }
            if (j == n) return i; //匹配
        }
        return -1; //虽然哈希值相同,但是全都不匹配
    }
};

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

3. BM算法

4. KMP算法

KMP实现与分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值