LeeCode 28. 实现 strStr()
思路:KMP算法求模式串的前缀数组:1)next数组初始化,j从-1开始(前缀数组右移一位,j也可以从0开始,从0开始的话后面更新则是j=next[j-1],从-1开始则更新为j=next[j]),next[0]=0;2)处理不匹配的情况;3)处理匹配的情况;4)更新next数组。模式串与文本串匹配:1)处理不匹配的情况;2)处理匹配的情况;3)如果文本串中出现了模式串,则返回第一个字符出现的位置。代码如下:
class Solution {
public void getNext(int[] next, String needle){
int j=-1;
next[0] = j;
for(int i=1; i<needle.length(); i++){
while(j >= 0 && needle.charAt(i) != needle.charAt(j+1)){ // 处理不想等的情况
j = next[j];
}
if(needle.charAt(i) == needle.charAt(j+1)){ // 处理相等的情况
j++;
}
next[i] = j; // 更新j
}
}
public int strStr(String haystack, String needle) {
int[] next = new int[needle.length()];
getNext(next, needle);
int j = -1;
for(int i=0; i<haystack.length(); i++){
while(j >= 0 && haystack.charAt(i) != needle.charAt(j+1)){ // 处理不匹配的情况
j = next[j];
}
if(haystack.charAt(i) == needle.charAt(j+1)){ // 处理匹配的情况
j++;
}
if(j == needle.length() - 1){ // haystack出现了needle字符串
return i-j;
}
}
return -1;
}
}
LeetCode 459.重复的子字符串
想法:类似于KMP求前缀数组,用笔算了一下几个样例的前缀数组,简单发现当-1的个数大于非-1的个数时,字符串s不能由其子串构成。提交没过。
思路:看了题解后,主要是卡在满足条件的判断那里,如果next[len-1]!=-1说明字符串s中存在相等的前后缀,若同时满足len % (len - next[len-1] -1) == 0,则s能由重复的子串构成,其中next[len-1] +1表示的是最长相同前后缀的长度,len - next[len-1] -1相当于找到第一个周期的长度,若这个周期能被整除,则说明数组是这个周期的循环。代码如下:
class Solution {
public boolean repeatedSubstringPattern(String s) {
int[] next = new int[s.length()];
int j = -1;
next[0] = -1;
for(int i=1; i<s.length(); i++){
while(j >= 0 && s.charAt(i) != s.charAt(j+1)){
j = next[j];
}
if(s.charAt(i) == s.charAt(j+1)){
j++;
}
next[i] = j;
}
if(next[next.length-1] != -1 && next.length % (next.length - next[next.length-1] - 1) == 0) return true;
return false;
}
}
字符串总结
写了几天的字符串题,印象最深的就是字符串反转,一般分三步,先去除掉多余的空格(如果题目需要的话),接着整体反转,最后局部单词反转,便可实现字符串反转的目的。其中最厉害的是左旋操作可以通过先局部反转再整体反转的方式来实现。要熟练掌握双指针解法,这在数组、链表和字符串都非常常用。
双指针回顾
之前用双指针来解决数组的删除操作还比较熟练,但在处理字符串反转时根本没有想到要用双指针法。解题时的第一思路便是使用库函数,中等的题也当作水题来写也是很没意思,这样下去不会有进步。
目前遇到的双指针解法场景:
1.数组:删除某个元素、有序数组的平方、三数之和。
2.链表:判断是否有环并求起点、反转链表、删除链表的倒数第N个元素。
3.字符串:字符串反转。