ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

第31天:面试比 KMP 还容易被问到的匹配算法!

2021-01-27 23:04:06  阅读:195  来源: 互联网

标签:字符 匹配 31 模式 aim 字符串 算法 KMP 问到


我准备了 1000 本电子书和计算机各领域高清思维导图 100 张,关注后回复【资源】,即可获取!更可回复【内推】加入 BAT 内推群!

第31天:面试比 KMP 还容易被问到的匹配算法!

01、实现 strStr()


字符串匹配类型的题目,是字符串类型中占比很大的一个支类。


题目:实现 strStr()


实现 strStr() 函数。给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。


示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2

示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

02、Sunday 匹配


Sunday 算法是 Daniel M.Sunday 于1990年提出的字符串模式匹配。其核心思想是:在匹配过程中,模式串发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。

因为该问是字符串匹配篇第一讲,所以先普及几个概念:

  • 串:串是字符串的简称
  • 空串:长度为零的串称为空串
  • 主串:包含子串的串相应地称为主串
  • 子串:串中任意个连续字符组成的子序列称为该串的子串
  • 模式串:子串的定位运算又称为串的模式匹配,是一种求子串第一个字符在主串中序号的运算。被匹配的主串称为目标串,子串称为模式串。

了解这些基本概念,回到这个算法。Sunday匹配不是说这人在周末发现了这个算法,而是这人名字叫星期天(可能父母总加班,所以起了这么个名)。听起来牛叉的不得了,其实是个啥意思:

假若我们的目标串为:Here is a little Hao

模式串为:little

一般来讲,字符串匹配算法第一步,都是把目标串和模式串对齐。不管是KMP,BM,SUNDAY都是这样。

第31天:面试比 KMP 还容易被问到的匹配算法!
而对于SUNDAY算法,我们从头部开始比较,一旦发现不匹配,直接找到主串中位于模式串后面的第一个字符,即下面绿色的 “s”。(这里说明一下,为什么是找模式串后面的第一个字符。在把模式串和目标串对齐后,如果发现不匹配,那肯定需要移动模式串。问题是需要移动多少步。各字符串匹配算法之间的差别也来自于这个地方,对于KMP,是建立部分匹配表来计算。BM,是反向比较计算移动量。对于SUNDAY,就是找到模式串后的第一个字符。因为,无论模式串移动多少步,模式串后的第一个字符都要参与下一次比较,也就是这里的 “s”)
第31天:面试比 KMP 还容易被问到的匹配算法!

找到了模式串后的第一个字符 “s”,接下来该怎么做?我们需要查看模式串中是否包含这个元素,如果不包含那就可以跳过一大片,从该字符的下一个字符开始比较。

第31天:面试比 KMP 还容易被问到的匹配算法!
因为仍然不匹配(空格和l),我们继续重复上面的过程。找到模式串的下一个元素:t

第31天:面试比 KMP 还容易被问到的匹配算法!
现在有意思了,我们发现 t 被包含于模式串中,并且 t 出现在模式串倒数第3个。所以我们把模式串向前移动3个单位:
第31天:面试比 KMP 还容易被问到的匹配算法!

有内味了,我们发现竟然匹配成功了,是不是很神奇?证明的过程今天暂且不谈(后面我会出一个算法证明篇,来证明之前讲过的一些算法。我需要你做的是,掌握上面这些!

捞干货,这个过程里我们做了一些什么:

  • 对齐目标串和模式串,从前向后匹配
  • 关注主串中位于模式串后面的第一个元素(核心)
  • 如果关注的字符没有在子串中出现则直接跳过
  • 否则开始移动模式串,移动位数 = 子串长度 - 该字符最右出现的位置(以0开始)

    03、算法应用


自然是把这个算法应用到我们的题目中咯...

根据分析,得出代码:(给一个保证你能看的懂的JAVA版本的)

//JAVA 
class Solution {
    public int strStr(String origin, String aim) {
        if (origin == null || aim == null) {
            return 0; 
        } 
        if (origin.length() < aim.length()) {
            return -1; 
        }
        //目标串匹配索
        int originIndex = 0;
        //模式串匹配索引
        int aimIndex = 0;
        // 成功匹配完终止条件:所有aim均成功匹配
        while (aimIndex < aim.length()) {
            // 针对origin匹配完,但aim未匹配完情况处理 如 mississippi sippia
            if (originIndex > origin.length() - 1) {
                return -1;
            }
            if (origin.charAt(originIndex) == aim.charAt(aimIndex)) {
                // 匹配则index均加1
                originIndex++;
                aimIndex++;
            } else {
                //在我们上面的样例中,第一次计算值为6,第二次值为13
                int nextCharIndex = originIndex - aimIndex + aim.length();
                //判断下一个目标字符(上面图里的那个绿框框)是否存在。
                if (nextCharIndex < origin.length()) {
                    // 判断目标字符在模式串中匹配到,返回最后一个匹配的index
                    int step = aim.lastIndexOf(origin.charAt(nextCharIndex));
                    if (step == -1) {
                        // 不存在的话,设置到目标字符的下一个元素
                        originIndex = nextCharIndex + 1;
                    } else {
                        // 存在的话,移动对应的数字(参考上文中的存在公式)
                        originIndex = nextCharIndex - step;
                    }
                    //模式串总是从第一个开始匹配
                    aimIndex = 0;
                } else {
                    return -1;
                }
            }
        }
        return originIndex - aimIndex;
    }
}

标签:字符,匹配,31,模式,aim,字符串,算法,KMP,问到
来源: https://blog.51cto.com/15076236/2608556

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有