字符串匹配

原创 2016年08月30日 14:57:20

模式匹配(模范匹配):
子串在主串中的定位称为模式匹配或串匹配(字符串匹配) 。

方法一 Brute-Force模式匹配算法(暴力匹配法)

  1. 算法思想
    s:目标串,sub:模式串
    s=“s0 s1 s2…sn-1”
    sub=“t0 t1 t2 …tm-1”
    从主串s的第i个字符开始与子串sub的第一个字符比较,如果相等则继续比较后续字符;否则从主串s的下一字符开始与子串sub的的第一个字符比较,依次类推。
    匹配成功返回sub中第一个字符在主串s中的位置,否则返回-1.

*主串总是从已匹配子串第一个字符的下一个字符开始(i-j+1),子串从第一个字符开始,两者进行比较,即S[i-j+1]和sub[0]比较。
2. 代码

 //从S的第pos位置开始查找子串T;
class Solution{
public:
    char *strStr(const char *S,int pos,const char* T){                   
    if(!*T) 
        return (char*)S;                                         
    int i,j;           //i:主串字符下标,j:子串字符下标                                                             
    i=pos-1;   //pos:第几个字符,从1开始;i:下标,从0开始                                                             
    j=0;
    while(i<strlen(S)&&j<strlen(T))
    {
        if(S[i]==T[j])  
            {i++;j++}
        else
        {i=i-j+1;j=0}
    }
    if(j>=strlen(T))  
        return i-(j-1);
    else    
        return  -1;    
    }
}

方法二 KMP算法

2.KMP算法思想
主串指针不回退,只增长。子串指针尽量后移,而不是像方法一中的总是从第一个元素开始。

在字符串s中寻找sub,当匹配到位置i时两个字符串不相等,这时我们需要将字符串T向前移动。常规方法是每次向前移动一位,但是它没有考虑前i-1位已经比较过这个事实,所以效率不高。事实上,如果我们提前计算某些信息,就有可能一次前移多位。假设i之前的字符串(T的子串)为f
f有如下特点:
A段字符串是f的一个前缀。
B段字符串是f的一个后缀。
A段字符串和B段字符串相等且长度为L。
所以前移k位之后,可以继续比较位置i的前提是T的前i-1个位置满足:长度为L=i-k-1的前缀A和后缀B相同。只有这样,我们才可以前移k位后从新的位置继续比较。前移只是一种形象的说法,在实际比较过程中是在T的最大公共长度之后进行再次比较。
next 思想见博客:http://blog.csdn.net/yutianzuijin/article/details/11954939
3.next函数
当主串i位置和子串j位置字符不匹配时,j要进行跳转,也就是指示子串比较位置的j要发生变化.

在求得了next[j]值之后,KMP算法的思想是:
设目标串(主串)为s,模式串为t ,并设i指针和j指针分别指示目标串和模式串中正待比较的字符,设i和j的初值均为1。若有si=tj,则i和j分别加1。否则,i不变,j退回到j=next[j]的位置,再比较si和tj,若相等,则i和j分别加1。否则,i不变,j再次退回到j=next[j]的位置,依此类推。直到下列两种可能:
(1) j退回到某个下一个[j]值时字符比较相等,则指针各自加1继续进行匹配。
(2)退回到j=-1,将i和j分别加1,即从主串的下一个字符s[i+1]模式串的t[0]重新开始匹配。
KMP算法如下:

//用KMP算法进行模式匹配,匹配返回位置,否则返回-1
//用静态方式保存字符串,s和t分别表示主串和模式串  
#define Max_Strlen 1024
int next[Max_Strlen];
int KMP_index (const char* S ,const char *T)
{  
    int  i=0 , j=0 ;     /*初始匹配位置设置 */
    while( (i<strlen(S))&&(j<strlen(T)))
    { 
        if ((j==-1)|| (S[i]==T[j]))  
            {  k++ ; j++ ; }
       else 
           j=next[j] ;
    }
    if (j>= strlen(T)) 
        return(k-t.length) ;
    else 
        return(-1) ;
}   

求next函数:用归纳法:
模式串的next[j]值只与模式串sub有关,由next函数定义可知:
(1)当j=1时,next[1]=0; 当j=0,next[0]=-1;
(2)设next[j]=k,即在模式串中存在:
t[1…k-1]=t[j-(k- 1)… j-1],其中k在1和j之间的某个最大值,
(3)此时求next[j+1]的值有两种可能:

a.该i处不匹配时i跳转到next[i]
(1)若位置i和位置next[i]处的两个字符相同(下标从零开始),则next[i+1]等于next[i]加1。即next[i+1]=next[i]+1=k+1;
(2)如果两个位置的字符不相同,我们可以将长度为next[i]的字符串继续分割,获得其最大公共长度next[next[i]],然后再和位置i的字符比较。这是因为长度为next[i]前缀和后缀都可以分割成上部的构造,如果位置next[next[i]]和位置i的字符相同,则next[i+1]就等于next[next[i]]加1。如果不相等,就可以继续分割长度为next[next[i]]的字符串,直到next[0]=-1为止。(递推法)
小结next求法:
next[0]=-1;
假设next[j]=k,则表示已找到j以前的最大重叠子串,sub[0]~sub[k-1];
当j和next[j]位置处的元素相等时:next[j+1]=next[j]+1=k+1;
当j和next[j]位置处的元素不相等时:next[j+1]=next[…next[next[j]]]+1;一定要找到一个位置next[…next[next[j]]],此位置的元素与j位置处元素相同,且此位置之前的元素与j位置之前的部分元素能够匹配上。

 /*  求模式串Tnext函数值并保存在next数组中  */
/*因为假设j+1位置处匹配失败了才求的next[j+1],之前的j+1是现在的j(有++操作),如果跳转到k后的位置与j处元素相等,则还是会在与主串匹配过程中失败,则还要继续跳转,也就是就next值,一直要找到最终那个不会再跳转的位置*/
void next(const char *T ,int next[] )
{
    int  j=0 ,k=-1;
    next[0]=-1;
    while (j<strlen(T))
    {  
        if ((k==-1)|| (T[k]==T[j]))
        {  
             k++ ; 
             j++ ;
             if ( T[k]!=T[j] )  
                 next[j]=k;                                            
            else 
                next[j]=next[k];        
        }
        else  k=next[k] ; 
    }
}  
版权声明:本文为博主原创文章,未经博主允许不得转载。

算法——字符串匹配之有限自动机算法

本文介绍了有限自动机(Finite Automata)字符串匹配算法。
  • chenhanzhun
  • chenhanzhun
  • 2014年10月08日 20:13
  • 3107

读书笔记—基于后缀数组的字符串匹配算法

字符串后缀(Suffix)是指从字符串某位置开始到结尾的字符串子串,其中包括原串以及空串。 后缀数组(suffix array)指的是某个字符串的所有后缀按字典顺序排序后得到的数组。组数中记录对应的起...
  • himilong
  • himilong
  • 2015年03月06日 22:12
  • 613

字符串匹配(后缀数组)

假设已经求出字符串S的后缀数组点击打开链接,现在要求字符串T在字符串S中出现的位置,只要通过二分搜索就可以在O(T*logS)时间内完成。当S比较大时,比O(T+S)的算法更为高效,所以需要对同样的字...
  • m0_37846371
  • m0_37846371
  • 2017年09月08日 13:38
  • 158

【CCFCSP】201409-3 字符串匹配

试题编号: 201409-3 试题名称: 字符串匹配 时间限制: 1.0s 内存限制: 256.0MB这是一道基础的字符串匹配问题,可以使用遍历的方法判断一字符串是否被另一字符串...
  • dizzz
  • dizzz
  • 2017年04月10日 20:17
  • 292

字符串匹配算法——利用有限自动机进行匹配

来源: http://www.cnblogs.com/jolin123/p/3443543.html 本文内容与《算法导论》中字符串匹配章节相关并部分摘录。   常用的字符串匹...
  • wangqing_199054
  • wangqing_199054
  • 2014年03月05日 11:05
  • 778

简单字符串匹配方法

字符串匹配在实际的开发过程中用的很多,比如大多数人喜欢ctrl+f的快捷的,无论是在代码里面还是在文本里面 下面我们一起介绍一种简单的字符串匹配方法,这也是我们大多数人容易想到的算法。   算法...
  • u013018721
  • u013018721
  • 2016年04月07日 20:32
  • 486

【HihoCoder】Trie树 (字符串匹配)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习...
  • sea_mo
  • sea_mo
  • 2014年07月17日 19:44
  • 1255

华为OJ——字符串匹配

字符串匹配 题目描述 题目标题: 判断短字符串中的所有字符是否在长字符串中全部出现 详细描述: 接口说明 原型: boolIsAllCharExist(char* pShortString,char*...
  • u010480899
  • u010480899
  • 2016年07月16日 20:27
  • 630

Linux shell 字符串匹配

最近进行脚本学习的时候,遇到了字符串匹配的问题,网上的内容也很乱,在这里我就写一个简单可行的方法吧。        首先假设一个场景:在一个文件夹里有很多后缀为sh的文件,那我怎么移动除了指定的某些...
  • li6727975
  • li6727975
  • 2015年01月02日 13:32
  • 3166

Python字符串匹配

Python中re模块提供了字符串匹配的函数,常用函数如下: 1.re.match()这个函数描述如下: match(pattern , string , [, flags]) 检查string...
  • qq_20903715
  • qq_20903715
  • 2017年11月16日 11:10
  • 29
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:字符串匹配
举报原因:
原因补充:

(最多只允许输入30个字)