她:点击收听
1 基本知识点
1、串中的元素是字符
2、操作的对象往往不再是单个数据元素,而是一组数据元素(子串)
3、串:由零个或多个字符组成的有限序列
4、子串:串中任意连续个字符组成的子序列
5、包含子串的串又被称为该子串的主串
6、真子串是指非空并且不为自身的子串
7、子串定位:子串在主串中的位置(在主串中查找子串第一次出现的位置)(也可以称为模式匹配或者模型匹配)
8、空串是不含有任何字符的串
9、组成串的数据元素只可以为字符
10、主串长度为n,子串长度为m,那么KMP算法的时间复杂度为O(m+n)
11、KMP算法的特点是:在模式匹配的时候指向主串的指针不会变小(只会不动或者向后移动)
2 串的模式匹配
子串的定位操作称为模式匹配
在主串中查找子串第一次出现的位置
如果匹配成功,那么返回子串在主串中第一次出现的位置;如果匹配失败,那么返回-1
…
int i = 0;
int j = 0;
//i为主串指针 j为子串指针
if(S.curlength<T.curlength)
return -1;
//S为主串 T为子串
//主串长度小于子串 匹配失败
while(i<S.curlength&&j<T.curlength){
if(S.data[i] == T.data[j]){
i++;
j++;
//对应字符相等就让指针向后移动
}else{
//对应字符不相等就让:
//主串指针回溯(由原来位置移动到下一个位置开始比较)
//子串从头开始
i = i-j+1;
j = 0;
}
}
if(j>=T.curlength)
return (i-T.curlength);
//匹配成功返回子串在主串中的位置
else
return -1;
总结:
3 KMP算法
主串不需要回溯,主串指针一直向后移动,只有子串指针回溯
当Si和Tj匹配失败的时候:
1 在子串中找到A和B两段是相等的
2 那么在主串中也对应C和D两段是相等的
3 所以说A和D两段是相等的
那么就可以从Tk开始和Si继续比较
(将子串的指针从j退回到k,主串的指针保留在i)
找到Tk的位置是关键
由图可得:在i = j = 9时匹配失败
需要将j回退到k = 3处,保持i不变
同时,将③称为首串,将④称为尾串
1 首串:是以子串的第一个字符开始
2 尾串:是以匹配失败位置的前一个字符结束
(所以说②和③一定相等)
找到首串和尾串是关键
(首串和尾串的长度应该小于原字符串的长度)
整型数组next:
在j位置匹配失败:回溯到k
next[j] = k
求解next数组:
next数组的前两个元素值一般是-1和0
分析:
1 走到a的时候,a的前面不存在首串和尾串,所以说a时赋值还是为0
2 走到b的时候,b的前面存在“a”为首串和尾串,长度为1,所以说b时赋值为1
3 走到c的时候,c的前面存在“ab”为首串和尾串,长度为2,所以说c时赋值为2
4 走到d的时候,d的前面存在“abc”为首串和尾串,长度为3,所以说d时赋值为3
由此可得:
解释:
1 当i和j走到9的时候,匹配失败
2 查看j为9时对应的next数组的值为3
3 将子串回溯到j=3继续开始比较
4 最后可以发现匹配成功
4 改进的KMP算法
那么nextVal数组的值是怎么求得的呢?
求解nextVal数组的值:
1 已知next数组
2 再去求解nextVal数组
3 第一个元素值为-1
4 剩下的元素的值需要找到next数组值对应元素相比较
5 如果元素相同,就用前面的值去替换后面的值
6 不相等就继续保留
7 nextVal数组完成
过程:
遇到nextVal为-1失配情况时,i++,j=0
5 题目解析
解析:
1 长度为1的字符串有n个
2 n、n-1...2
3 那么求和可知:((n+2)*(n-1))/2
4 等价于D选项
解析:
1 使用KMP的next数组方法
2 对于模式串t而言,next数组值为:
a b a a b c
-1 0 0 1 1 2
3 当i等于j等于5时候失配,那么j将回溯到2,i不发生改变
已知模式串(子串),求对应的next数组的值
解析:
1 第一个元素为-1
2 第二个元素为0
3 注意找首串和尾串
注意:j为7时对应为4
解析:
1 求next数组值
2 求nextVal数组值
6 算法设计题
判断给定的串是否为回文串
例如:noon、level都是回文串
//代码实现
int main(){
string arr;
int i,j,k=0;
getline(cin,arr);
for(i=0,j=arr.length()-1;i<j;i++,j--){
if(arr[i]!=arr[j])
break;
}
if(i>=j)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
return 0;
}