给定两个字符串str和match,长度分别为N和M。实现一个算法,如果字符串str中含有子串match,则返回match在str中的开始位置,不含有则返回-1
若出现了多次,则按照升序输出所有出现位置
[要求]
时间复杂度为
第一行一个字符串str
第二行一个字符串match
输出若干个数,分别为match在str中出现的位置,从0开始标号。
若不存在输出-1
acbc bc
2
acbc bcc
-1
ababab ab
0 2 4
保证字符集为小写字母
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
char[] str1 = br.readLine().toCharArray();
char[] str2 = br.readLine().toCharArray();
if(str1.length < str2.length){
System.out.println(-1);
}else{
StringBuilder sb = new StringBuilder();
int[] next = getNextArr(str2);
int i1 = 0, i2 = 0;
int find = kmp(str1, str2, i1, i2, next);
while(find > -1){
sb.append(find + " ");
i1 = find + 1; // i1不断后移,与str2匹配
find = kmp(str1, str2, i1, i2, next);
}
System.out.println(sb.length() == 0? -1: sb.toString().trim());
}
}
private static int kmp(char[] str1, char[] str2, int i1, int i2, int[] next) {
if(i1 + str2.length >= str1.length) return -1;
while(i1 < str1.length && i2 < str2.length){
if(str1[i1] == str2[i2]){ // 字符相等,两个字符都移动
i1 ++;
i2 ++;
}else if(next[i2] > -1){
i2 = next[i2]; // 不相等且还能往前跳,则i2往前面跳
}else{
i1 ++; // str2已经跳到0了还没法匹配成功,就只能移动str1的指针了
}
}
return i2 == str2.length? i1 - i2: -1;
}
private static int[] getNextArr(char[] str) {
if(str.length == 1) return new int[]{-1};
int[] next = new int[str.length];
next[0] = -1;
int i = 2, prev = 0;
while(i < str.length){
if(str[i - 1] == str[prev]){
next[i] = prev + 1; // 最长与后缀相等的前缀长度+1
prev ++;
i ++;
}else if(prev > 0){
prev = next[prev]; // 不相等就往前跳
}else{
next[i] = prev;
i ++;
}
}
return next;
}
} #KMP算法
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String match = sc.nextLine();
KMP k = new KMP();
List<Integer> result = k.kmp(str,match);
//return result;
for(int i : result){
System.out.print(i);
System.out.print(" ");
}
}
}
class KMP{
public List<Integer> kmp(String str,String match){
char[] matches = match.toCharArray();
char[] strs = str.toCharArray();
int[] next = getNext(matches);
List<Integer> result = new ArrayList<>();
int curmatch = 0;
int index = 0;
while(index<strs.length){
while(curmatch != -1 && strs[index] != matches[curmatch]){
curmatch = next[curmatch];
}
curmatch++;
if(curmatch == matches.length){
result.add(index-matches.length+1);
curmatch = next[curmatch-1];
}else
index++;
}
if(result.isEmpty())
result.add(-1);
return result;
}
private int[] getNext(char[] chars){
int[] next = new int[chars.length];
next[0] = -1;
for(int i = 1;i<chars.length;i++){
int k = i-1;
while(k != 0 && chars[i-1] != chars[next[k]]){
k = next[k];
}
next[i] = next[k]+1;
}
return next;
}
}