KMP算法详解3:next表代码实现

建议观看整个详解视频。
KMP算法详解1:https://www.bilibili.com/video/BV1vR4y1j7aL/
KMP算法详解2:https://www.bilibili.com/video/BV1Lr4y1h7Dv/
KMP算法详解3:https://www.bilibili.com/video/BV1LZ4y1o7aQ/

/**
 *
 *
 * KMP 详解3:next表代码实现。
 *
 *
 */
public class KMP {

    public static int[] next(String pattern) {

        // 1. 暴力递归
//        char[] chars = pattern.toCharArray();
//        int[] next = new int[chars.length];
//        for (int i = 0; i < chars.length; i ++) {
//            next[i] = recursion(chars, i);
//        }
//        return next;

        // 2. 递归 + 备忘录(记忆搜索)
//        char[] chars = pattern.toCharArray();
//        int[] next = new int[chars.length];
//        // 初始化,next[0] = -1;next[1] = 0;next[2+] = -2;
//        next[0] = -1;
//        for (int i = 2; i < chars.length; i++) {
//            next[i] = -2;
//            memorandum(chars, i, next);
//        }
//        return next;


        // 3. 迭代
        return dp3(pattern);
    }

    //
    // 截止到index之前的串(即p[index]子串)的最长相同前后缀 递归
    // index 对应求解 i+1
    private static int recursion(char[] p, int index) {
        if (index < 2) {
            return index - 1; // 0:-1,1:0
        }

        int i = index - 1;
        int n = i;

        while (true) {
            n = recursion(p, n);
            // 1. 在某一次循环中得到结果退出。
            if (p[n] == p[i]) {
                return n + 1;
            }
            //2. 前部分缩减到0,最后是比较p[0] 与 p[i],如果相等,结果则为1,否则为0。
            if (n == 0) {
                return 0;
            }
        }
    }

    // 递归+备忘录
    private static int memorandum(char[] p, int index, int[] next) {
        if (next[index] != -2) {
            return next[index];
        }
        int i = index - 1;
        int n = i;

        while (true) {
            n = memorandum(p, n, next);
            // 1. 在某一次循环中得到结果退出。
            if (p[n] == p[i]) {
                next[index] = n + 1;
                return next[index];
            }
            //2. 前部分缩减到0,最后是比较p[i] 与 p[0],如果相等,结果则为1,否则为0。
            if (n == 0) {
                next[index] = 0;
                return next[index];
            }
        }
    }


    // 迭代
    private static int[] dp(String pattern) {
        char[] p = pattern.toCharArray();
        int length = p.length;
        int[] next = new int[length];
        next[0] = -1;
        if (length <= 2) {
            return next;
        }

        //
        int index = 2;

        int n = next[index - 1];
        while (index < length) {
            if (n < 0 || p[index-1] == p[n]) {
                next[index] = n + 1;
                index ++;
                n = next[index - 1];// next[index++]=++n
                continue;
            }
            // 可用小技巧:因为 next[0]=-1,next[1]=0, 可令两个条件合二为一
            // 当n=0时,继续走 n=next[n](即 n=-1),那么 next[index++]=0(=++n)
//            if (n == 0) {
//                next[index] = 0;
//                index ++;
//                // n = next[index - 1] (=0)
//                continue;
//            }
            // 逐一递减的方式查找最长相同前后缀!
            n = next[n];
        }
        return next;
    }

    // 迭代
    private static int[] dp2(String pattern) {
        char[] p = pattern.toCharArray();
        int length = p.length;
        int[] next = new int[length];
        next[0] = -1;
        if (length <= 2) {
            return next;
        }

        int index = 2;
        int n = next[index - 1];
        while (index < length) {
            // 这里总是要减一,有没有办法优化呢?
            // index=index-1,即index从1开始,注意index++要改++index,且条件要改成index<length-1,:dp3
            if (n < 0 || p[index-1] == p[n]) {
                next[index++] = ++n;
            } else {
                // 逐一递减的方式查找最长相同前后缀!
                n = next[n];
            }
        }
        return next;
    }

    // 迭代
    private static int[] dp3(String pattern) {
        char[] p = pattern.toCharArray();
        int length = p.length;
        int[] next = new int[length];
        next[0] = -1;
        if (length <= 2) {
            return next;
        }

        int index = 1;
        int n = next[index];
        int iMax = length - 1;
        while (index < iMax) {
            if (n < 0 || p[index] == p[n]) {
                next[++index] = ++n;
            } else {
                // 逐一递减的方式查找最长相同前后缀!
                n = next[n];
            }
        }
        return next;
    }
}

单元测试:

public class KMPTest {

    @Test
    public void next() {
        String pattern = "xxaxxxb";
        int[] next = KMP.next(pattern);
        String result = Arrays.stream(next).mapToObj(i -> i + "").collect(Collectors.joining(" "));
        assertEquals("-1 0 1 0 1 2 2", result);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值