支持单字通配符的Sunday模糊匹配算法
前言
忙碌的春节过去了(吐槽一下,现在南京不给放炮仗,真是越来越没有年味了,不但是礼炮,连擦炮、摔炮都买不到),终于能闲下来学习和写博文了。今天填一下上篇文章留下的坑。实现一个支持单字通配符的Sunday模糊匹配算法
假定需求
给定一个 haystack 字符串和一个 needle 字符串,实现一个支持 '?'
的单字通配符匹配算法。在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始),如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "l?o" 输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "b?a" 输出: -1
- 本文算法复杂度中的
是模式串的长度, 是主串的长度。 i
代表主串指针,j
代表模式串指针,?
代表单字通配符
朴素解法(暴力匹配)
每次j
向后移动1步,逐个对比,遇到?
就跳过;遇到不匹配的,i
向后移动1步, j
再从头对比
实现
1 | class Solution { |
复杂度分析
- 预处理时间复杂度:无
- 匹配时间复杂度:
- 空间复杂度:
Sunday解法
标准Sunday需要什么改进?
之前介绍过标准的Sunday算法是通过偏移表,在匹配失败时,确定需要移动多少,然后让i
去位移
但由于?
可以代表任意一个字符,所以我们无法在预处理阶段就确定需要移动多少,只能根据模式串中最后的?
确定最少需要移动多少。那么我们就需要让?
的偏移量动态更新
如何动态更新通配符的偏移量
每次对比中j
只要遇到了?
,就将偏移量更新进去。如果j
从来没遇到过?
,就使用通配符最小偏移。
字符偏移表和通配符偏移量如果同时存在,应该如何选择?
答案:选择字符偏移表
为什么:因为能直接将模式串和匹配的末尾字符的下一位对齐
实现
1 | class Solution { |
复杂度分析
- 预处理时间复杂度:
- 匹配时间复杂度:
- 平均:
- 最好:
- 最差:
- 平均:
- 空间复杂度:
实际情况测试
特征码匹配是单字通配符模糊匹配的应用场景之一
这里使用C#实现的特征码匹配对GTAV
进程主模块内存进行搜索
测试环境:主串长度:将近8000万,Debug模式
朴素算法(暴力匹配)

Sunday算法

总结


根据以上测试用例,可以看出。在特征码匹配的实际应用中,Sunday算法拥有极高的性能优势
- 耗时:Sunday算法比朴素算法快了3-4倍
- 对比次数:Sunday算法比朴素算法减少了4-6倍