暴力匹配算法和KMP算法

问题:如果有两个字符串str1,str2,我们要判断str2是否是str1的子字符串,我们可以采用暴力匹配算法,和KMP算法解决

1.暴力匹配算法

1.将两个字符串都变成字符数组;

        char []s1=str1.toCharArray();
        char []s2=str2.toCharArray();

2.判断s1[i]和s2[j]是否相等

(1.)不相等则i=i-j+1; j=0; 每次匹配失败s1的索引只往后移动一位
暴力匹配算法和KMP算法_第1张图片

暴力匹配算法和KMP算法_第2张图片
(2.)相等那么j++,i++
暴力匹配算法和KMP算法_第3张图片

暴力匹配算法和KMP算法_第4张图片
直到s1的空格和s2的D不匹配则进行(1)
暴力匹配算法和KMP算法_第5张图片

暴力匹配算法和KMP算法_第6张图片
完整java代码如下:

package com.yg.algorithm;/*
@author  Mu_Mu
@date    2020/3/18  9:27
*/

public class ViolenceMatch {
    public static void main(String[] args) {
    String str1="hahahahehehahe";
    String str2="hehehahe";
        System.out.println("index:"+violenceMath(str1,str2));
    }

    public static int violenceMath(String str1, String str2) {
        char []s1=str1.toCharArray();
        char []s2=str2.toCharArray();
        int s1Len=s1.length;
        int s2Len=s2.length;
        int i = 0;//s1的索引
        int j=0;//s2的索引
        while (i < s1Len && j < s2Len) {
            if (s1[i] == s2[j]) {
                i++;
                j++;
            } else {
                i = i - (j - 1);
                j=0;
            }
        }
        if (j == s2Len) {
            return i - j;
        } else {
            return -1;
        }

    }
}

2.KMP算法

1.建立一个部分匹配表:

部分匹配表:用一个一维数组next[]表示字符串中相同前缀后缀的最大长度,next[0]恒等于0;
next[j] = k 代表p[j] 之前的模式串子串中,有长度为k 的相同前缀和后缀

如字符串str=“A”;
它不能踩分为前缀和后缀所以它的部分匹配表为next:[0];

字符串str=“AA”;
它可以拆分为前缀A,和后缀A;
因为第二个A加进来后相同前缀和后缀的最大长度为1所以next[1]=1;

它的部分匹配表为 next:[0,1];

字符串str=“AAB”;
它可以拆分为前缀A,AA和后缀AB,B
因为B加进来后相同前缀和后缀的最大长度为0所以next[2]=0;

它的部分匹配表为 next:[0,1,0];

在KMP匹配中,当模式串中j 处的字符失配时,下一步用next[j]处的字符继续跟文本串匹配,相当于模式串向右移动j - next[j] 位。

构建部分匹配表

//获取到一个字符串(子串)的部分匹配表
    public static int[] kmpNext(String dest) {
        //创建一个next数组保存部分匹配值
        int[] next = new int[dest.length()];
        //当只有一个字符时匹配值为0
        next[0]=0;
        for (int i = 1, j = 0; i < dest.length(); i++) {

            while (j>0&&dest.charAt(i) != dest.charAt(j)) {
            //每次寻找部分匹配表j前面的一个匹配值
                j=next[j-1];
            }
            //字符相等匹配值加一
            if (dest.charAt(i) == dest.charAt(j)) {
                j++;
            }
            next[i]=j;
        }
        return next;
    }

除了s1[i]和s2[j]不相等时其余操作基本和暴力匹配相识

不相等时:
每次移动距离为失配字符前一个位置 - 失配字符前一个位置对应的next 值 j=next[j-1];

暴力匹配算法和KMP算法_第7张图片

暴力匹配算法和KMP算法_第8张图片

完整java代码实现:

package com.yg.algorithm;/*
@author  Mu_Mu
@date    2020/3/18  10:58
*/

public class KmpAlgorithm {
    public static void main(String[] args) {
        String str1="hahahahheheheha";
        String str2="heheheha";


        int []next=kmpNext(str2);
        System.out.println("index:"+kmpSearch(str1,str2,next));
    }

    //获取到一个字符串(子串)的部分匹配表
    public static int[] kmpNext(String dest) {
        //创建一个next数组保存部分匹配值
        int[] next = new int[dest.length()];
        //当只有一个字符时匹配值为0
        next[0]=0;
        for (int i = 1, j = 0; i < dest.length(); i++) {

            while (j>0&&dest.charAt(i) != dest.charAt(j)) {
            //相当于已遍历字符个数-对应部分匹配表的匹配值
                j=next[j-1];
            }
            //字符相等匹配值加一
            if (dest.charAt(i) == dest.charAt(j)) {
                j++;
            }
            next[i]=j;
        }
        return next;
    }

    public static int kmpSearch(String str1, String str2, int[] next) {
        for (int i = 0, j = 0; i < str1.length(); i++) {
            while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
                j=next[j-1];
            }
            if (str1.charAt(i) == str2.charAt(j)) {
                j++;
            }
            if (j == str2.length()) {
                return i-j+1;
            }
        }
        return -1;
    }
}

图片以及部分文字参考:
https://www.cnblogs.com/zhangtianq/p/5839909.html

你可能感兴趣的:(算法)