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;
}
}