字符串匹配问题(暴力匹配,KMP算法)

package com.example.test_utils.algorithm;

/**
 * @author bao-fa
 * @date 2021/10/15
 * 字符串模式匹配,匹配成功,返回子串在主串中第一个字符的下标,匹配失败返回-1
 * 暴力算法和kmp算法、kmp优化算法未完成
 */
public class FindIndex {
    public static void main(String[] args) {
        //构造较长的主串。
        StringBuilder str = new StringBuilder();
        for (double i = 0; i < 10000; i++) {
            str.append('a');
        }
        String s = str.append('c').toString();
        //构造较长的子串
        StringBuilder tr = new StringBuilder();
        for (double i = 0; i < 1000; i++) {
            tr.append('a');
        }
        String t = tr.append('c').toString();
        //测试两种算法的效率差异
        //暴力匹配算法 输出程序执行时间,输出查找位置
        long startTime = System.currentTimeMillis();
        int indexByViolence = violenceMatch(s, t);
        long endTime = System.currentTimeMillis();
        long costTime = endTime-startTime;
        System.out.println("暴力算法执行时间"+costTime);
        System.out.println("暴力算法查找位置为"+indexByViolence);
        //KMP匹配算法
        startTime = System.currentTimeMillis();
        int indexByKMP = kmpMatch(s, t);
        endTime = System.currentTimeMillis();
        costTime = endTime-startTime;
        System.out.println("KMP执行时间"+costTime);
        System.out.println("KMP查找位置为"+indexByViolence);
        if (indexByKMP == indexByViolence) {
            System.out.println("两种方法位置一致");
        }else {
            System.out.println("两种方法位置不一致");
        }
    }

    private static int violenceMatch(String s, String t) {
        //标记主串的
        int i =0;
        //标记子串的
        int j =0;
        while (i < s.length() && j < t.length()) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
                j++;
            }else{
                i = i - j + 1;
                j = 0;
            }
        }
        //匹配成功,则j==t.length()
        if (j == t.length()) {
            return i-j;
        }else {
            return -1;
        }
    }

    private static int kmpMatch(String s, String t) {
        //构造一个子串的next数组,存储子串的字符next值
        int[] next = new int[t.length()];
        for (int i = 0; i < next.length; i++) {
            //获取字符的next值
            next[i] = getNextValue(i + 1,t);
        }
        //标记主串的
        int i =0;
        //标记子串的
        int j =0;
        while (i < s.length() && j < t.length()) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
                j++;
            }else{
                //子串第一个字符匹配失败,则下次匹配时j的下标仍要为0,继续从子串第一个位置开始匹配,主串i右移一位。
                if (j == 0) {
                    i = i+1;
                }
                //子串非第一个字符匹配失败,则下次匹配时子串应该从已匹配的子串最长匹配值开始匹配。主串i的位置不变。
                else{
                    j = next[j-1];
                }
            }
        }
        //匹配成功,则j==t.length()
        if (j == t.length()) {
            return i-j;
        }else {
            return -1;
        }
    }

    //获取next数组这里还可以再优化。这里处理的不好,会导致当数据过大时,kmp算法比暴力算法执行效率更慢。
    private static int getNextValue(int tSonLength,String t) {
        if (tSonLength == 1) {
            return 0;
        }
        //前缀子串
        String prefixT;
        //后缀子串
        String suffixT;
        //最长前后缀匹配长度
        int maxMatch = 0;
        //有多少个字符串前后缀需要匹配
        int matchNum = tSonLength-1;
        //前缀子串的末尾下标 (字符串的第一个位置也是0)
        int i = 1;
        //后缀子串的起始下标
        int j = tSonLength - 1;
        while (matchNum > 0) {
            //字符串前缀,substring方法是前闭后开的原则
            prefixT = t.substring(0, i);
            suffixT = t.substring(j, tSonLength);
            if (prefixT.equals(suffixT)) {
                maxMatch = i;
            }
            //前缀末尾下标右移
            i++;
            //后缀子串起始下标左移
            j--;
            //匹配次数减少一次
            matchNum--;
        }
        return maxMatch;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值