欢迎关注我的B站账号:卍卍子非鱼卍卍
字符串模式匹配
现有目标串s:"aaaaab"
与模式串t:"aaab"
要求返回s
中与t
相同的子串起始下标位置index
,在该题中,为2
暴力法(Brute-Force)
算法思路
1.定义指针i,j
分别指向s,t
的开头
2.当i
和j
均为移动至尽头时,进行循环:
2.1 如果i,j
处字符相同,说明暂时匹配。i,j
各加1
2.2 如果i,j
处字符不相同,回退指针
由于此时已经向前移动了j
步,所以i
回退到i - j + 1
的位置,即回退目前匹配的长度后再前进1位,然后将j
重置为0
3.循环结束后,判断j
与t
长度之间的关系,若j = t.length()
,说明经过上述循环,t
被完全遍历,说明s
中有与t
相同的子串,那么此时i - t.length()
的位置,即为字串的起始位置。否则,说明没找到,返回-1
代码
class Solution_1 {
/**
* 现有目标串s与模式串t,要求返回s中与t相同的字串起始下标位置,若没有,返回-1
*
* @param s 目标串
* @param t 模式串
* @return s中与t相同的字串起始下标位置
*/
public int bruteForce(String s, String t) {
int i = 0, j = 0;
while (i < s.length() && j < t.length()) {
if (s.charAt(i) == t.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j >= t.length()) {
return i - t.length();
} else {
return -1;
}
}
}
KMP算法
算法思路
KMP算法十分巧妙(巧妙到我到现在也没完全搞懂)
KMP算法定义了一个数组next[]
,其中next[j]
记录了模式串t
在j
位置前最多有多少个字母连成的字符串与t
从头开始的字符串相同
听不懂?很正常,下面用一个数学表达式进行表示(建议死记硬背):
以模式串t = "aaaab"
为例,它的next[]
数组如下表示:
算法思路如下:
1.首先获取next[]
数组,写在getNext(String t, int[] next)
方法中,我真的很想在这里解释清楚这个代码是怎么实现的,但真的很难解释清楚,所以这里我建议你就像记住冒泡排序一样把它记在脑子里,下次写的时候别带脑子纯靠背
2.回到主方法KMP(String s, String t)
中,首先调用getNext(String t, int[] next)
方法获取t
的next[]
数组,然后依旧定义指针i,j
分别指向s,t
的开头
3.在循环的过程中略有不同:当i,j
处的字符不相同时,i
指针回退到next[j]
所记录的位置,即i = next[j]
4.循环结束后的判断与暴力法相同
代码
class Solution_2 {
/**
* 现有目标串s与模式串t,要求返回s中与t相同的字串起始下标位置,若没有,返回-1
*
* @param s 目标串
* @param t 模式串
* @return s中与t相同的字串起始下标位置
*/
public int KMP(String s, String t) {
int[] next = new int[t.length()];
getNext(t, next);
int i = 0, j = 0;
while (i < s.length() && j < t.length()) {
if (j == -1 || s.charAt(i) == t.charAt(j)) {
i++;
j++;
} else {
j = next[j];
}
}
if (j >= t.length()) {
return i - t.length();
} else {
return -1;
}
}
private void getNext(String t, int[] next) {
int j = 0, k = -1;
next[0] = -1;
while (j < t.length() - 1) {
if (k == -1 || t.charAt(j) == t.charAt(k)) {
j++;
k++;
next[j] = k;
} else {
k = next[k];
}
}
}
}