字符串匹配 sunday算法

原题:lintcode题目

字符串查找(又称查找子字符串),是字符串操作中一个很有用的函数。你的任务是实现这个函数。

对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。

如果不存在,则返回 -1


字符串匹配最常见的就是kmp算法,不过kmp算法对于我来说过于的复杂,我在网上查找,发现了更为简单,易于理解的sunday算法

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


unday是一个字符串 模式匹配算法。算法的概念如下:
Sunday算法是Daniel M.Sunday于1990年提出的一种字符串 模式匹配算法算法。其核心思想是:在匹配过程中,模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较,它在发现不匹配时,算法能跳过尽可能多的 字符以进行下一步的匹配,从而提高了匹配效率。
假设在发生不匹配时S[i]≠T[j],1≤i≤N,1≤j≤M。此时已经匹配的部分为u,并假设字符串u的长度为L。如图1。明显的,S[L+i+1]肯定要参加下一轮的匹配,并且T[M]至少要移动到这个位置(即模式串T至少向右移动一个字符的位置)。
1 Sunday 算法不匹配的情况
分如下两种情况:
(1) S[L+i+1]在模式串T中没有出现。这个时候模式串T[0]移动到S[L+i+1]之后的字符的位置。如图2。
2 Sunday 算法移动的第 1 种情况
(2)S[L+i+1]在模式串中出现。这里S[L+i+1]从模式串T的右侧,即按T[M-1]、T[M-2]、…T[0]的次序查找。如果发现S[L+i+1]和T中的某个字符相同,则记下这个位置,记为k,1≤k≤M,且T[k]=S[L+i+1]。此时,应该把模式串T向右移动M-k个字符的位置,即移动到T[k]和S[L+i+1]对齐的位置。如图3。
3 Sunday 算法移动的第 2 种情况
依次类推,如果完全匹配了,则匹配成功;否则,再进行下一轮的移动,直到 主串S的最右端结束。该算法最坏情况下的 时间复杂度为O(N*M)。对于短模式串的匹配问题,该算法执行速度较快。
Sunday算法思想跟BM算法很相似,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。
在这里给出代码.


int strStr(const char *source, const char *target) {
      if(source == NULL || target == NULL)
            return -1;
    
     int i,j,pos=0;
    int len_s,len_d;
    int next[256]={0};//next数组保存在target中出现字符顺序,这样在匹配的时候不需要重新查找,

    len_d=strlen(target);
    for(j=0;j<256;++j)                       //初始化next数组,如果next没有在target中出现,next为target长度+1,即跳过整个target长度
        next[j]=len_d + 1;
    for(j=0;j<len_d;++j)                        //设置next数组
        next[target[j]-'0']=j+1; <span style="white-space:pre">		</span>//next的字符在target出现,者next值为target内的顺序+1
    while( pos<(len_s-len_d+1) )               //遍历原串          
    {
        i=pos;
        for(j=0;j<len_d;++j,++i)              //比较
        {
            if(source[i]!=target[j])                //一旦不匹配,原串就按照next跳转
            {
                pos+=next[source[pos+1]-'0'];//如果下一个字符在target出现,则跳过next的值,否则跳过这个target长度
                break;
            }
        }
        if(j==len_d)
            return pos;
    }
    return -1;                  
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值