今天一共学习字符串相关的两道题,个人认为需要学习的内容不少,难度也较大,分别是LeetCode.28和LeetCode.459。
LeetCode.28找出字符串中第一个匹配项的下标
本题和前面的题一样,都可以暴力破解。使用两层for循环将字符串中的每一个子串遍历出来,和待匹配项比较,返回第一次匹配成功的下标,如果遍历完字符串都没有匹配成功,则返回-1。
public static int strStr(String haystack,String needle){
for (int i = 0; i < haystack.length(); i++) {
if (haystack.charAt(i)==needle.charAt(0)) {
for (int j = i; j <haystack.length(); j++) {
if (haystack.substring(i,j+1).equals(needle)){
return i;
}
}
}
}
return -1;
}
注意,该算法的时间复杂度为O(N*M),N为字符串的长度,M为待匹配串的长度。而这种类型的题目,关于在一个字符串中寻找子串,有一个专门的算法,叫做KMP算法。这个算法在学数据结构的时候就学到过,不过只学了理论,实际的代码实现并没有思考过,今天重点内容就是这个KMP算法。
这个算法一共有两步,第一步是构建next数组,第二步是按照next数组寻找子串,KMP算法的时间复杂度为O(N+M)。
第一步,构建next数组。next数组有三种实现方式,第一种为原始实现,第二种将next[0]置成-1,并将后方原始实现的数组元素整体后移,第三种是将原始数组的next每一个元素-1。第二种元素在代码实现和理解上会有稍稍的改进,但也是需要了解最原始的实现方式,这里使用第一种也就是最原始的实现方式。这里将会直接说next的数组实现方式,具体原理可以参考印度老师的视频,我认为是讲的最清晰的,在b站上或者油管都可以搜到。首先定义一个长度和待匹配字符串长度相同的整型数组。将数组的第一个元素置为0,定义两个指针,j指向字符串首元素,i指向字符串第二个元素。如果i和j指向元素相等,那么next[i]的值为j+1,接着将j和i都向后移动一位。如果i和j指向元素不相等,并且j>0时,即在j不指向首元素且i,j指向元素不相等时,将j指向next数组种j前一位处,即j=next[j-1]
,如果还不相等,继续重复回溯,直到相等,同样这时next[i]=j+1
。如果一直回溯到j=0,这时如果相等,那么同样next[i]=j+1
,也就是这时next[i]的值为1。如果j=0所指元素仍不相等,则next[i]=0
,将i后移一位,继续匹配。
public static</