算法-子串出现的位置

90 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

题目来源:leetcode-cn.com/leetbook/re…

题目

实现 strStr() 函数。

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

说明:当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

输入:haystack = "hello", needle = "ll"
输出:2

思路分析

在 JS 中是有IndexOf方法可以对 字符串可以直接索引定位到子串的位置,那么基本就只要使用一行代码就能实现这个算法。但是如果没有这个方法的话,一个简单的思路就是一个个字符进行匹配:子串从头开始和主串进行匹配,如果匹配失败了,子串再次从头开始匹配,主字符串就下一个字符继续匹配。直到子串都遍历结束都没有中断主串的遍历,那么说明存在,就可以当前的位置减去子串的位置,就是子串的位置。

其实这是一道典型的KMP算法题,KMP算法的本质就是减少重复计算,在上面的解法中我们比较时如果匹配失败那么子串就需要重新计算,想想如果遇到在最后一步比较失败的时候,然后子串又要从头开始,是不是有点像在做无用功,所以KMP算法就是想让你每次检验时,主串要从上一次比较的下一个字符开始,就是我们已经成功后的数据时可以再次利用的

代码实现

public int strStr(String haystack, String needle) {
        if (needle.length() == 0)
            return 0;
        int i = 0;
        int j = 0;
        int[] next = new int[needle.length()];
        getNext(needle, next);
        while (i < haystack.length() && j < needle.length()) {
            if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
                i++;
                j++;
            } else {
                j = next[j]; // j回到指定位置
            }
            if (j == needle.length())
                return i - j;
        }
        return -1;
    }

    private void getNext(String p, int next[]) {
        int len = p.length();
        int i = 0;
        int j = -1;
        next[0] = -1;//这个默认的,
        while (i < len - 1) {
            if (j == -1 || p.charAt(i) == p.charAt(j)) {
                i++;
                j++;
                next[i] = j;
            } else

                j = next[j];
        }
    }