我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「 陈皮的JavaLib」第一时间阅读最新文章,回复【 资料】,即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板。
@TOC
题目
实现 strStr() 函数。给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。当 needle 是 空字符串 时我们应当返回 0 。
示例1:
- 输入: haystack = "hello", needle = "ll"
- 输出:2
示例2:
- 输入:haystack = "aaaaa", needle = "bba"
- 输出:-1
示例3:
- 输入:haystack = "aaaaa", needle = ""
- 输出:0
题目来源:LeetCode
分析
字符串匹配,
最简单的
,无非暴力匹配
,但这效率是最低
的。
如果不自己实现,现有很多 api 也都实现了此功能,例如String
的indexOf
方法就能达到此效果。
但是此题目是让我们自己实现,说到字符串匹配问题,最有名的无非是KMP算法
。KMP算法
的核心思想
是用模式串(即本题目的needle)
构建一个next数组
:
- next 数组各值的含义:代表当前字符之前的字符串中,有
多大长度的相同前缀
。- 例如如果 next[j] = k,代表 j 之前的字符串中有最大长度为 k 的相同前缀。
- 意味着在某个字符失配时,该字符对应的 next 值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到 next[j] 的位置)。
- 如果 next[j] 等于0,则跳到模式串的开头字符,若 next[j] = k 且 k > 0,代表下次匹配跳到j之前的某个字符,而不是跳到开头,即跳过了 k 个字符。
实现
package com.chenpi;
/**
* @Description 实现 strStr()
* @Author Mr.nobody
* @Date 2021/1/23
* @Version 1.0
*/
public class StrStr {
public static int strStr(String haystack, String needle) {
// 文本串长度小于模式串,明显匹配不到
if (haystack.length() < needle.length()) {
return -1;
}
// 利用 KMP 算法构建 next 数组
int[] next = buildNext(needle);
int i = 0, j = 0;
while (i < haystack.length() && j < needle.length()) {
if (haystack.charAt(i) == needle.charAt(j)) {
// 匹配,两个下标都向后
j++;
i++;
} else if (j == 0) {
// 开头处匹配失效
i++;
} else {
// 利用 KMP,回溯到具体位置
j = next[j];
}
}
return j == needle.length() ? i - j : -1;
}
// KMP算法
// next数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。
// 例如如果next[j]=k,代表j之前的字符串中有最大长度为k的相同前缀后缀。
// 意味着在某个字符失配时,该字符对应的next值会告诉你下一步匹配中,模式串应该跳到哪个位置(跳到next[j]的位置)。
// 如果next[j]等于0,则跳到模式串的开头字符,若next[j]=k且k>0,代表下次匹配跳到j之前的某个字符,而不是跳到开头,即跳过了k个字符。
private static int[] buildNext(String needle) {
// 记录模式串needle每个字符匹配失效后应该回溯的位置,即next[j]为在j处匹配失效后,下一个匹配(回溯)的位置,
int[] next = new int[needle.length()];
int j;
// 因为第0个字符匹配失效,肯定还是从0个字符开始,所以i的从1开始
for (int i = 1; i < needle.length(); i++) {
j = i - 1;
while (j > 0 && needle.charAt(i - 1) != needle.charAt(next[j])) {
j = next[j];
}
if (j <= 0) {
next[i] = 0;
} else {
next[i] = next[j] + 1;
}
}
return next;
}
public static void main(String[] args) {
System.out.println(strStr("hello", "ll"));
System.out.println(strStr("aaaaa", "bba"));
System.out.println(strStr("aaaaa", ""));
}
}
输出结果
2
-1
0
Leetcode执行结果