字符串匹配算法1:暴力匹配算法
https://blog.youkuaiyun.com/lqy971966/article/details/99770472
字符串匹配算法2:KMP算法
https://blog.youkuaiyun.com/lqy971966/article/details/105712559
字符串匹配算法3:Boyer-Moore 算法
https://blog.youkuaiyun.com/lqy971966/article/details/106026651
1. 问题
有一个主串S,和一个模式串P,现在要查找P是否是主串S中的的子串。
主串 S串: abcd
模式串P串: bcd
2. 解决思想
2.1 举例
第一次匹配,a!=b,模式串往后移动一位。
第二次匹配,b=b,匹配后一位
第三次匹配,c=c,匹配后一位
第四次匹配,d=d,匹配完成。
如上图所示,暴力匹配的思路:依次用模式串匹配主串串的每一位,若模式串第一位匹配失败,则匹配主串的第二位,依次类推。
2.2 匹配思想
思想:
1. 依次从主串的首字符开始,与模式串逐一进行匹配;
2. 遇到失配时,则移到主串的第二个字符,将其与模式串首字符比较,逐一进行匹配;
3. 重复上述步骤,直至能匹配上,或剩下主串的长度不足以进行匹配。
3. 代码
假设现在主串S匹配到 i 位置,模式串P匹配到 j 位置,则有:
-
如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;
-
如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。
//入参:pcSrc为主串abcd, pcDst为模式串 bcd int BF_Match(char *pcSrc, char *pcDst) { int iSrcLoop, iDstLoop, iTmp; int iSrclen = strlen(pcSrc); int iDstlen = strlen(pcDst); /* for循环遍历主串,从头开始匹配模式串; 匹配失败,主串往后移动一位,继续匹配,依次。 注意: 这里主串每往后移动时, 需要计算主串剩余长度需要大于模式串长度,否则匹配无意义 */ for(iSrcLoop = 0, iDstLoop = 0; iSrcLoop <= iSrclen - iDstlen; iSrcLoop++, iDstLoop = 0) { iTmp = iSrcLoop; /* while循环遍历模式串,模式串匹配中主串, 则模式串和主串都后移一位继续匹配,否则跳出 */ while( (pcSrc[iTmp] == pcDst[iDstLoop]) & (iDstLoop < iDstlen) ) { iTmp++; iDstLoop++; } // matched OK if(iDstLoop == iDstlen ) { return iSrcLoop; } } // [pcDst] is not a substring of [pcSrc] return -1; }
4. 时间复杂度:
iSrcLoop 在主串移动次数(外层的for循环)有 n−p(iSrclen- iDstlen ) 次,在失配时 iDstLoop 移动次数最多有(p-1)iDstLoop−1次(最坏情况下);
因此,复杂度为 O(n*p)
5. 暴力匹配缺点:
5.1 重复匹配
上一次匹配失败后,下一次匹配的位置
- 主串的起始位置 = 上一轮匹配的起始位置 T + 1;
- 模式串的起始位置 = 首字符P[0]。
如此未能利用已经匹配上的字符的信息,造成了重复匹配。
5.2 例子
主串T=“ababcabcacbab”,
模式串P=“abcac”
比如:第一次匹配失败时,主串、模式串失配位置的字符分别为 a 与 c,
下一次匹配时主串、模式串的起始位置分别为T[1]与P[0];
而在模式串中c之前是ab,未有重复字符结构,因此T[1]与P[0]肯定不能匹配上,这样造成了重复匹配。
直观上,下一次的匹配应从T[2]与P[0]开始。
参考:
https://blog.youkuaiyun.com/v_july_v/article/details/7041827
https://www.cnblogs.com/en-heng/p/5091365.html