代码随想录 Day9
今日任务
28.找出字符串中第一个匹配项的下标
459.重复的子字符串
字符串总结
双指针总结
语言:Java
KMP算法实现
- 明确几个关键问题:
① 为何要使用 next 数组?
当匹配失败时,我们不需要再从头寻找,而是直接从匹配前缀后边一位继续进行比较操作;
② 时间复杂度:模式串长度 m,文本串长度 n,生成 next 数组 O(m),文本串匹配 O(n),一共是 O(m+n),大大节省了时间成本。 - 明确几个关键步骤:
① 初始化:i 和 j,i 表示最后一个后缀元素所在位置;j 表示最后一个前缀元素所在位置,也表示最长前缀长度;
② 处理前后缀不同的情况:要用 while 不断回退,注意数据越界问题;
③ 处理前后缀相同的情况:j++ 即可。 - 明确几个概念
① 前缀:不包含最后一个元素
② 后缀:不包含第一个元素
class Solution {
public void myKMP(String needle){
int[] next = new int[needle.length()];
//j放外面初始化
//1.1 初始化j
int j = 0;
//获取next数组
//1.2 初始化i
for(int i = 1; i < needle.length(); i++){
//int j = 0;
//2. 处理前后缀不同的情况
while(j > 0 && needle.charAt(i) != needle.charAt(j)){
j = next[j - 1];
}
//3. 处理前后缀相同的情况
if(needle.charAt(i) == needle.charAt(j)){
j++; //j全程表示长度,一直对j操作就对了
}
next[i] = j;
}
}
}
28. 找出字符串中第一个匹配项的下标
考点:KMP
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/
class Solution {
public int strStr(String haystack, String needle) {
if(haystack.length() < needle.length()){
return -1;
}
int[] next = new int[needle.length()];
//获取next数组
int j = 0;
for(int i = 1; i < needle.length(); i++){
//int j = 0;
while(j > 0 && needle.charAt(i) != needle.charAt(j)){
j = next[j - 1];
}
if(needle.charAt(i) == needle.charAt(j)){
j++;
}
next[i] = j;
}
int i = 0;
j = 0;
while(i < haystack.length()){
while(j < needle.length()
&& i < haystack.length()
&& haystack.charAt(i) == needle.charAt(j)){
i++;
j++;
}
if(j == needle.length()){
return i - needle.length();
}
if(i < haystack.length()
&& j > 0
&& haystack.charAt(i) != needle.charAt(j)){
j = next[j - 1];
i--;
}
i++;
}
return -1;
}
}
459. 重复的子字符串
考点:KMP
链接:https://leetcode.cn/problems/repeated-substring-pattern/
思路讲解:代码随想录
几个方面:
① 最小重复字串:当一个字符串由重复字串组成时,最长相等前后缀不包含的部分的就是最小重复字串;
② (仅针对由重复的子字符串构成的字符串)假设重复出现的子字符串长度为x,原字符串中包含n个子字符串,最长相同前后缀包含m个子字符串,则必有n - m = 1
,也就是说nx % (n - m)x = 0
一定成立,由此得到我们的判断方式:len % (len - next[len-1]) = 0
意味着原字符串由重复子字符串构成;
③ 需要注意的是,如果最后一个元素的next值为0,意味着整个字符串最长相等前后缀的长度为0,此时len == len - next[len - 1]
,最终len % (len - next[len - 1]) == 0
也是成立的,但它是不符合条件的;
④ 这道题中使用KMP算法主要是为了得到整个字符串最长相等前后缀,也就是最后一个字符处的next值。
class Solution {
public boolean repeatedSubstringPattern(String s) {
if(s.length() == 1){
return false;
}
int len = s.length();
int[] next = new int[len];
int j = 0;
for(int i = 1; i < len; i++){
while(j >0 && s.charAt(i) != s.charAt(j)){
j = next[j - 1];
}
if(s.charAt(i) == s.charAt(j)){
j++;
}
next[i] = j;
}
//如果最后一位最长前后缀长度为0,是不符合题意的,要排除掉
//ababac
if(next[len - 1] != 0 && len % (len - next[len - 1]) == 0){
return true;
}
else{
return false;
}
}
}