字符串匹配

1.串:字符串,0个或多个字符序列

字符串求长度 strlen

字符串比大小 strcmp strncmp

字符串连接 strcat

字符串拷贝 strcpy

字符串匹配 BF(brute force 暴力算法 朴素算法)

​ KMP(对BF算法的优化)

2.子串和真子串的区别? 真子串不包括自身

​ 空串和空格串的区别? “” " "

3.“abcd”

" " “a” “b” “c” “d”

“ab” “bc” “cd”

“abc” “bcd”

“abcd”

子串个数:(1+n)*n/2+1

真子串个数:(1+n)*n/2

4.BF算法

主串: ”ababcabcdabcde" 子串:“abcd”

目的:在主串中找到子串的开始位置

主串和子串一一比较

​ 如果相等,i++,j++,比较下一个

​ 如果不相等,i=i-j+1,j=0,继续比较

​ j走出范围,表示找到了, return i-j

优缺点:优点:思想简单,好实现

​ 缺点:效率低下,O(n*m)

/*
BF算法:
1.两两比较,如果相等,i++,j++,接着向后比
2.如果不相等,i回退(回退到这一趟开始的下一个位置,i=i-j+1),j回退到开始位置(j=0)
3.主串的i是否走出范围,不能表示字符串是否匹配成功,所以只能用子串表示
4.如果子串的j走出范围,肯定找到了,返回i-j   不然没有找到,匹配失败,返回-1
*/
int BF_Search(const char* str,const *sub,int pos)
{
	assert(str!=NULL&&sub!=NULL);
    if(pos<0||pos>=strlen(str))
    {
		pos=0;
    }
    int len_str=strlen(str);//主串的长度信息
    int len_sub=strlen(sub);//子串的长度信息
    int i=pos;//主串开始的位置
    int j=0;//子串开始的位置
    
    while(i<len_str&&j<len_sub)
    {
		if(str[i]==sub[j])//如果相等,两者同时向后走,i++,j++
        {
			i++;
            j++;
        }
        else//不相等 i回退到i-j+1  j回退到0  
        {
			i=i-j+1;
            j=0;
        }   
    }
    //此时while循环推出   两种情况,要么i走出范围   要么j走出范围
    if(j>=len_sub)//如果子串的j走出范围,找到了,返回i-j
    {
        return i-j;
    }
    else//否则没有找到,匹配失败,返回-1
    {
        return -1;
    }
}

5.KMP算法【思想:i不回退】

如果发生失配:

​ a>子串前面的字符如果互不相等,那么i完全不用回退

​ b>子串前面的字符有相等,怎么办?

​ 可以回退,i回退有价值;但是,i回退后价值的操作,可以让j代替,从而让i不用回退

优点:将每一比较失败的信息都利用上,将其中不可能的操作屏蔽掉,不再浪费时间去比较,而是直接比较有可能的操作

6.怎么计算j回退的合适位置k?

对于子串来说,每一个位置都有可能发生匹配失败,所以每一个位置发生失配的时候,j都应该有一个回退的合适位置k

(j有可能子啊任何位置失配,所以任何位置都应该有合适的回退位置k)

​ k:如果发生失配,从失配位置向前看,看子串是否存在两个真子串,一个项头,一个项尾;如果存在,则k就是这个真子串的长度

next数组,只和子串有关,跟主串无关

" abcabc" " ababcabcd" " ababcababcaba"

“-100012” “-100120120” “-1001201234567”

int *Get_next(const char*sub)//专门针对子串获取其next数组
{
    assert(sub!=NULL);
    int len_sub=strlen(sub);
    int *next=(int*)malloc(sizeof(int)*len_sub);
    assert(next!=0);
    
    next[0]=-1;
    next[1]=0;
    
    int j=1;
    int k=0;
    
    //通过已知推位置,j是已知,则j+1是未知
    while(j+1<len_sub)//未知位置需要合法,所以做了一个判断
    {
        if(sun[j]==sub[k]||(k==-1)//要么相等k++赋值,要么不相等k一直回退,触发保底机制
        {
            //next[++j]=++k;
        	k++;
            j++;
            next[j]=k;
        }
        else
        {
            k=next[k];
        }
    }
    return next;
}
int KMP_Search(const char* str,const *sub,int pos)
{
	assert(str!=NULL&&sub!=NULL);
    if(pos<0||pos>=strlen(str))
    {
		pos=0;
    }
    int len_str=strlen(str);//主串的长度信息
    int len_sub=strlen(sub);//子串的长度信息
    int i=pos;//主串开始的位置
    int j=0;//子串开始的位置
    
    int *next=Get_next(sub);
    
    while((j==-1)||i<len_str&&j<len_sub)
    {
		if(str[i]==sub[j])//如果相等,两者同时向后走,i++,j++
        {
			i++;
            j++;
        }
        else//不相等   
        {
            j=next[j];
        }   
    }
    //此时while循环推出   两种情况,要么i走出范围   要么j走出范围
    if(j>=len_sub)//如果子串的j走出范围,找到了,返回i-j
    {
        return i-j;
    }
    else//否则没有找到,匹配失败,返回-1
    {
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值