1.查找子字符串问题:
For a given source string and a target string, you should output the first index(from 0) of target string in source string.
If target does not exist in source, just return -1
.
算法要求:输入源字符串与目标字符串,输入目标字符串在源字符串中的首字符的下标(下标从0开始计算),
如果没有目标字符串返回-1
解决思路1:双重循环(暴力匹配),第一个循环遍历源字符串,第二个循环遍历目标字符串,时间复杂度O(n^2)
private SubStringIndex(source:string,target:string):number{
//特殊情况检测
if(target.length>source.length||!source||!target){
return -1;
}
//减target.length是因为第一层循环不用走最后的几个字符,因为一定不会匹配的
let res=-1;
for(let i=0;i<=source.length-target.length;i++){
if(source[i]==target[0]){//首字符相同才开始第二层循环
let temp=true;
for(let j=0;j<target.length;j++){
if(source[i+j]!=target[j]){
temp=false;
break;
}
}
if(temp){
res=i;
return res;//第一个找到就退出
}
}
}
return res;
}
解决思路2:KMP算法(K、M、P三个大佬想出来的,所以叫KMP)
如果在第二层循环中出现字符不同时,第一层不是退回首字符,而是到一个合适的地方,不浪费之前的计算,那么上面的算法是不是会更加高效呢?
KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。
具体实现是通过getNext获得第一层循环的迭代指针在第二层循环失败后应该到达的位置,即当源串中的某个字符跟目标串中的某个字符匹配失配时,模式串下一步应该跳到哪个位置。
如源字符串中在j 处的字符跟目标串在i 处的字符匹配失配时,下一步用next [j] 处的字符继续跟文本串i 处的字符匹配,相当于模式串向右移动 j - next[j] 位。
//输入源字符串,返回一个next数组
private getNext(s:string):number[]{
let next=[];
next[0]=-1;
let i=0;
let j=-1;
while(i<s.length-1){
if(j==-1||s[i]==s[j]){
i++;
j++;
next[i]=j;//记录下一个相同字符的下标
}else{
j=next[j];
}
}
return next;
}
这里的wile可能很难一下就看懂,关键是j=next[j]不太好理解,其实这个while就是一个for的变种,它遍历了一次源字符串,走的每一个i都会设置next[i],如果这个i位置没有对应可到的next就设置为0,