前言
力扣第二十八题 实现 strStr()
如下所示:
实现 strStr()
函数。
给你两个字符串 haystack
和 needle
,请你在 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哦。
这一题有两种方式来解决:
- 双层循环暴力匹配(方案一)
- KMP算法(俗称看毛片算法)
双层循环此处不做过多的解释,大致的意思就是第一层循环遍历 str
选择起始元素,第二层循环选择 str
中长度为 target.length
的字符串判断是否与 target
相等,如相等返回相应结果即可。
图解KMP算法
此处以 str = ABCABCABF
、 target = ABCABF
tips:说实话我现在还是不知道部分匹配表如何构建,等后续弄明白了再来填坑8!
KMP我觉得 阮一峰,这一篇文章写的挺好的,推荐。
KMP算法的核心思想就是:构建一张部分匹配表,碰到不匹配的元素时可以移动到下一个位置。(具体的步骤见下文)
第一步,构建部分匹配表
ABCABF
的部分匹配表如下所示:
部分匹配表
next
中的值表示:当前位置及以前的元素中的前缀
和后缀
最长的共有元素长度
例如next[4]
(4为下标,表示第五个元素),表示ABCAB
中的前缀
和后缀
最长的共有元素长度,ABCAB
的前缀有A, AB, ABC, ABCA
,后缀有BCAB, CAB, AB, B
,显然最长的共有元素为AB
,即next[4] = 2
移动的公式: 移动位数 = 已匹配的字符数 - 对应的部分匹配值(就是将整个字符移动到下一个可以匹配的位置)
第一次出现字符不相等
第一次移动,此时 F != A
,已匹配的字符为 ABCAB
长度为 5,ABCAB
的部分匹配值为 2,故移动的位置为 5 - 2 = 3
,如下图所示:
第二次移动,此时 C != A
,已匹配的字符为 AB
长度为 2,AB
的部分匹配值为 0,故移动的位置为 2 - 0 = 2
,如下图所示: