目录
KMP算法:字符串查找,寻找匹配的字符串,避免重复匹配,增加时间复杂度
前缀表:求得的最长相同前后缀的长度就是对应前缀表的元素,一次遍历实现
字符不匹配,回退 = 指针移到前一字符具有相应前后缀位置后,直到字符匹配或len=0
KMP算法:字符串查找,寻找匹配的字符串,避免重复匹配,增加时间复杂度
28. 实现 strStr():请你在 haystack
字符串中找出 needle
字符串出现的第一个位置 O(m+n)
前缀表:求得的最长相同前后缀的长度就是对应前缀表的元素,一次遍历实现
-
字符不匹配,回退 = 指针移到前一字符具有相应前后缀位置后,直到字符匹配或len=0
-
字符匹配,在当前相同前后缀长度上+1
-
给当前元素的前缀表赋值
class Solution {
public int strStr(String haystack, String needle) {
int j = 0, i = 0;
int[] next = buildNext(needle);
while(i < haystack.length()){//i一直后移
while(j > 0 && haystack.charAt(i) != needle.charAt(j)){
j = next[j-1];//回退到前一个可以匹配的字符
}
if(haystack.charAt(i) == needle.charAt(j)){
j++;//匹配则指针后移
}
if(j == needle.length()){//匹配成功
return i-j+1;
}
i++;
}
return -1;
}
public int[] buildNext(String s){
int[] next = new int[s.length()];
int pre_len = 0;//最长的相等的真前缀与真后缀的长度
for(int i = 1; i < s.length(); i++){
while(pre_len > 0 && s.charAt(pre_len) != s.charAt(i)){
pre_len = next[pre_len-1]; //字符不匹配,就一直回退
//存在a-1,就要判断a>0,防止角标越界
}
//最大相等长度要么比前一个字符多一个pre_len++,要么跳转到pre_len=0
if(s.charAt(pre_len) == s.charAt(i)){
pre_len++;//比前一个匹配字符多一个
}
next[i] = pre_len;//
}
return next;
}
}
459. 重复的子字符串:给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。eg:s = "abcabcabc"
class Solution {
public boolean repeatedSubstringPattern(String s) {
int n = s.length();
int[] next = new int[n];
int len = 0;
for(int i = 1; i < n; i++){
while(len > 0 && s.charAt(i) != s.charAt(len)){
len = next[len-1];
}
if(s.charAt(i) == s.charAt(len)){
len++;
}
next[i] = len;
}
if((next[n-1] > 0)&&(next[n-1] % (s.length()-next[n-1]) == 0)){
return true;
}
return false;
}
}
巧妙运用 反转字符串(反转由双指针实现)(减少空间复杂度)
剑指 Offer 58 - II. 左旋转字符串:把字符串前面的若干个字符转移到字符串的尾部
//方法一:借助额外空间
// class Solution {
// public String reverseLeftWords(String s, int n) {
// char[] so = s.toCharArray();
// char[] sl = new char[n];
// for(int i = 0; i<n; i++){
// sl[i] = so[i];
// }
// for(int i = n; i<s.length(); i++){
// so[i-n] = so[i];
// }
// for(int i = 0; i<n; i++){
// so[i+s.length()-n] = sl[i];
// }
// return new String(so);
// }
// }
//方法二:借助反转
class Solution {
public String reverseLeftWords(String s, int n) {
char[] so = s.toCharArray();
reverse(so,0,n-1);
reverse(so,n,s.length()-1);
reverse(so,0,s.length()-1);
return new String(so);
}
public void reverse(char[] s,int l, int r){
while(l<r){
char t = s[l];
s[l] = s[r];
s[r] = t;
l++;
r--;
}
}
}
151. 颠倒字符串中的单词:颠倒后的字符串中不能存在多余空格、前导空格和尾随空格。
输入:s = " hello world " 输出:"world hello"
class Solution {
public String reverseWords(String s) {
char[] sinit = s.toCharArray();
char[] res = new char[s.length()];
int count = 0, resi = 0, si = s.length()-1;
while(si >= 0){
while(si >= 0 && sinit[si] == ' '){
si--;
}
int index = si;//单词右侧
while(si >= 0 && sinit[si] != ' '){
si--;//单词左侧
}
for(int i = si+1; i<=index; i++){
res[count++] = sinit[i];
if(i == index && si != -1 ){
res[count++] = ' ';
}
}
}
if(res[count-1] == ' '){
count--;
}
return new String(res,0,count);
}
}