leetcode-28-实现 strStr() 函数(KMP)

实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回  -1 。

说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

查看视频
油管阿三哥讲KMP查找算法,中英文字幕,人工翻译,简单易懂
帮你把KMP算法学个通透!(理论篇)

1. 实现前缀表

/**
 * 前缀表是用来回退的,记录了当模式串与文本串不匹配时,模式串应该从哪里重新匹配。
 * 前缀表具有告诉我们当前位置匹配失败,跳到之前匹配过的地方的能力。
 * 
 * 模式串与前缀表对应位置的数字表示的就是:下标i之前(包括i)的字符串中,有多大长度的相同前后缀。
 * 
 * next数组就可以是前缀表,但是很多实现都是把前缀表统一减一(或者右移一位,初始位置为-1)之后作为next数组。
 * 这并不涉及到KMP的原理,而是具体实现方式不同嗯,next数组即可以就是前缀表,也可以是前缀表统一减一(或者右移一位,初始位置为-1)。
 * 
 * 下面的 kmpNext 方法是:next数组就是前缀表。
 *
 * @param pattern
 * @return
 */
private int[] kmpNext(String pattern) {
    int len = pattern.length();
    // 初始化前缀表,与模式串长度相同
    int[] next = new int[len];
    // 规定前缀表第一个元素值为0
    next[0] = 0;
    // i指向后缀终止位置,index指向前缀终止位置即前缀的长度
    int i = 1, index = 0;
    while (i < len) {
        // 如果在pattern上位置i和位置index上的字符相同时,把 index(前缀的长度)+1 赋值给next[i],index和i向前移动一位
        if (pattern.charAt(i) == pattern.charAt(index)) {
            next[i] = index + 1;
            index++;
            i++;
        } else {
            // 如果在pattern上位置i和位置index上的字符不相同时,把前缀的位置index移动到next[index - 1]
            if (index != 0) {
                index = next[index - 1];
                // 如果在pattern上位置i和位置index上的字符不相同时,且已经把前缀的位置index移动到next数组第0位置上还是不相等,
                // 就把next数组位置i上赋值为0,并把i往前移动一位
            } else {
                next[i] = 0;
                i++;
            }
        }
    }
    return next;
}

2. 实现KMP搜索

private int kmpSerach(String haystack, String needle) {
    int[] next = kmpNext1(needle);
    // hi,ni两个指针分别指向文本串和模式串的开头
    int hi = 0, ni = 0;
    while (hi < haystack.length() && ni < needle.length()) {
        // 如果文本串和模式串分别在hi和ni上元素相同,把hi和ni同时往前移动一位
        if (haystack.charAt(hi) == needle.charAt(ni)) {
            hi++;
            ni++;
        } else { // 当模式串与文本串不等时
            if (ni == 0) { 
                // 当模式串第一个位置字符与文本串不等时,文本串指针向前移动一位
                hi++;
            } else {
                // 把模式串按照next数组向前回溯
                ni = next[ni - 1];
            }
        }
    }

    if (ni == needle.length()) {
        return hi - ni;
    }

    return -1;
}
posted @ 2021-05-20 18:23  hj0612  阅读(61)  评论(0编辑  收藏  举报