字符串匹配之Sunday 算法

Sunday 算法

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

匹配过程

  从前往后匹配,在匹配失败时关注的是主串中参加匹配的最末位字符的下一位字符。

    • 如果该字符没有在模式串中出现则直接跳过,即移动位数 = 模式串长度 + 1;
    • 否则,其移动位数 = 模式串长度 - 该字符最右出现的位置(以0开始) = 模式串中该字符最右出现的位置到尾部的距离 + 1。

案例(转载自(小浩学算法—字符串系列:实现sunday匹配))

  

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

PNG

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

PNG

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

PNG

因为仍然不匹配(空格和l),我们继续重复上面的过程。找到模式串的下一个元素:t

PNG

现在有意思了,我们发现 t 被包含于模式串中,并且 t 出现在模式串倒数第3个。所以我们把模式串向前移动3个单位:

PNG

 

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

 

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

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

 

应用

实现 strStr()

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

示例 1:

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

示例 2:

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

class Solution {
public:
    int strStr(string haystack, string needle) {
        int len_h = haystack.length();
        int len_n = needle.length();
        if (len_h==0)
            if(len_n==0)
                return 0;
            else
                return -1;

        if (len_h<len_n)
            return -1;
        
        int hIndex = 0;
        int nIndex = 0;
        while(nIndex < len_n)
        {
            if(hIndex > len_h-1)
                return -1;
            if(haystack[hIndex] == needle[nIndex])
            {
                hIndex++;
                nIndex++;
            }
            else
            {
                int nextIndex = hIndex-nIndex+len_n;
                if(nextIndex<len_h)
                {
                    int step = needle.rfind(haystack[nextIndex]);
                    if(step==-1)
                    {
                        hIndex = nextIndex+1;
                    }
                    else
                    {
                        hIndex = nextIndex-step;
                    }
                    nIndex = 0;
                }
                else
                    return -1;
            }
        }
        return hIndex-nIndex;
    }
};

 

posted @ 2020-07-13 15:24  r1-12king  阅读(456)  评论(0编辑  收藏  举报