力扣第二十八题-实现 strStr()

1,031 阅读3分钟

这是我参与更文挑战的第25天,活动详情查看: 更文挑战

前言

力扣第二十八题 实现 strStr() 如下所示:

实现 strStr() 函数。

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

说明

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

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

示例 1

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

示例 2

输入:haystack = "aaaaa", needle = "bba"
输出:-1

示例 3

输入:haystack = "", needle = ""
输出:0

一、思路

str:原字符串
target:目标字符串

这一题是手动实现Java中String的Api indexOf,就是找到字符串 needle 在字符串 str 中的位置。如果 target 为空,则返回 0 即可。

手动实现,手动实现,手动实现!重要的事情说三遍,不能使用Java自带的Api哦。

这一题有两种方式来解决:

  1. 双层循环暴力匹配(方案一)
  2. KMP算法(俗称看毛片算法)

双层循环此处不做过多的解释,大致的意思就是第一层循环遍历 str 选择起始元素,第二层循环选择 str 中长度为 target.length 的字符串判断是否与 target 相等,如相等返回相应结果即可。

图解KMP算法

此处以 str = ABCABCABFtarget = ABCABF

tips:说实话我现在还是不知道部分匹配表如何构建,等后续弄明白了再来填坑8!

KMP我觉得 阮一峰,这一篇文章写的挺好的,推荐。

KMP算法的核心思想就是:构建一张部分匹配表,碰到不匹配的元素时可以移动到下一个位置。(具体的步骤见下文)

第一步,构建部分匹配表

ABCABF 的部分匹配表如下所示:

部分匹配表 next 中的值表示:当前位置及以前的元素中的 前缀后缀 最长的共有元素长度
例如 next[4] (4为下标,表示第五个元素),表示 ABCAB 中的 前缀后缀 最长的共有元素长度,ABCAB 的前缀有 A, AB, ABC, ABCA,后缀有 BCAB, CAB, AB, B,显然最长的共有元素为 AB,即 next[4] = 2

image.png

移动的公式: 移动位数 = 已匹配的字符数 - 对应的部分匹配值(就是将整个字符移动到下一个可以匹配的位置)

第一次出现字符不相等

image.png

第一次移动,此时 F != A,已匹配的字符为 ABCAB 长度为 5,ABCAB 的部分匹配值为 2,故移动的位置为 5 - 2 = 3,如下图所示:

image.png

第二次移动,此时 C != A,已匹配的字符为 AB 长度为 2,AB 的部分匹配值为 0,故移动的位置为 2 - 0 = 2,如下图所示:

image.png

逐位比较,发现都相同,返回结果下标 5 即可。如下图所示:

image.png

二、实现

穷举法

实现代码

    public int strStr(String haystack, String needle) {
        int n = haystack.length(), m = needle.length();
        for (int i = 0; i + m <= n; i++) {
            boolean flag = true;
            for (int j = 0; j < m; j++) {
                if (haystack.charAt(i + j) != needle.charAt(j)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return i;
            }
        }
        return -1;
    }

测试代码

    public static void main(String[] args) {
        int[] nums = new int[8];
        new Number28().strStr("abababca", "abca");
    }

结果

image.png

KMP算法

实现代码

此处分两部,先求部分匹配表。再使用部分匹配表来求字符串的位置

    /**
     * KMP算法(俗称:看毛片)
     */
    public int strStr(String str, String target) {
        int tLen = target.length();
        if (tLen == 0) {
            return 0;
        }
        // 部分匹配表
        int[] next = getNext(target.toCharArray());
        for (int i = 0, j = 0; i < str.length(); i++) {
            while (j > 0 && str.charAt(i) != target.charAt(j)) {
                j = next[j - 1];
            }
            if (str.charAt(i) == target.charAt(j)) {
                j++;
            }
            if (j == tLen) {
                return i - tLen + 1;
            }
        }
        return -1;
    }

    /**
     * 部分匹配表(Partial Match Table)生成
     * 思路:从模式字符串的第一位(注意,不包括第0位)开始对自身进行匹配运算
     */
    public int[] getNext(char[] needle) {
        int len = needle.length;
        int[] next = new int[len];
        int j=0;
        // next的第一个值一定为0,所以从1开始
        for (int i = 1; i < len; i++) {
            while (j > 0 && needle[i] != needle[j]) {
                j = next[j - 1];
            }
            if (needle[i] == needle[j]) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }

结果

image.png

三、总结

哭惹,怎么看毛片没有穷举快呀tnt!是我写的有什么问题吗?

感谢看到最后,非常荣幸能够帮助到你~♥