首页 > 试题广场 >

KMP算法

[编程题]KMP算法
  • 热度指数:3588 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定两个字符串str和match,长度分别为N和M。实现一个算法,如果字符串str中含有子串match,则返回match在str中的开始位置,不含有则返回-1
若出现了多次,则按照升序输出所有出现位置
[要求]
时间复杂度为

输入描述:
第一行一个字符串str
第二行一个字符串match


输出描述:
输出若干个数,分别为match在str中出现的位置,从0开始标号。
若不存在输出-1
示例1

输入

acbc
bc

输出

2
示例2

输入

acbc
bcc

输出

-1
示例3

输入

ababab
ab

输出

0 2 4

备注:
保证字符集为小写字母
既然题目说要用KMP算法,那就老老实实写个KMP算法来匹配就好了。而由于需要找到所有匹配的位置,因此要不断移动第一个字符串的起始指针来循环执行KMP算法来找到所有位置。
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;
    }
}

发表于 2021-11-17 10:31:33 回复(1)
#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;
    }
}

发表于 2020-02-12 13:32:00 回复(0)