KMP算法练习题
LeetCode链接:28. 找出字符串中第一个匹配项的下标
1.题目描述
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
1 2 3 4
| 输入:haystack = "sadbutsad", needle = "sad" 输出:0 解释:"sad" 在下标 0 和 6 处匹配。 第一个匹配项的下标是 0 ,所以返回 0 。
|
示例 2:
1 2 3
| 输入:haystack = "leetcode", needle = "leeto" 输出:-1 解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
|
提示:
- $1 <= haystack.length, needle.length <= 10^4$
haystack
和 needle
仅由小写英文字符组成
2.题解
2.1 暴力解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public int strStr(String haystack, String needle) { if (needle.length() == 0) return 0;
for (int i = 0; i <= haystack.length() - needle.length(); i++) { int j = 0; while (j < needle.length() && haystack.charAt(i + j) == needle.charAt(j)) { j++; } if (j == needle.length()) { return i; } } return -1; } }
|
2.2 KMP算法
2.2.1 KMP写法1(不减1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public int strStr(String haystack, String needle) { if (needle.length() == 0) return -1;
int[] next = getNext(needle);
int j = 0; for (int i = 0; i < haystack.length(); i++) { while (j > 0 && haystack.charAt(i) != needle.charAt(j)) j = next[j - 1]; if (haystack.charAt(i) == needle.charAt(j)) j++; if (j == needle.length()) return i - needle.length() + 1; } return -1; }
public int[] getNext(String s) { int n = s.length(); int[] next = new int[n]; int j = 0;
next[0] = 0;
for (int i = 1; i < n; i++) { while (j > 0 && s.charAt(i) != s.charAt(j)) j = next[j - 1]; if (s.charAt(i) == s.charAt(j)) j++; next[i] = j; } return next; } }
|
2.2.2 KMP写法2(减1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| class Solution { public int strStr(String haystack, String needle) { if (needle.length() == 0) return -1;
int[] next = getNext(needle); int j = -1;
for (int i = 0; i < haystack.length(); i++) { while (j >= 0 && haystack.charAt(i) != needle.charAt(j + 1)) j = next[j];
if (haystack.charAt(i) == needle.charAt(j + 1)) j++;
if (j == needle.length() - 1) return i - needle.length() + 1; } return -1; }
public int[] getNext(String s) { int n = s.length(); int[] next = new int[n]; int j = -1; next[0] = -1;
for (int i = 1; i < n; i++) { while (j >= 0 && s.charAt(i) != s.charAt(j + 1)) j = next[j];
if (s.charAt(i) == s.charAt(j + 1)) j++; next[i] = j; } return next; } }
|
2.3 KMP算法改进
nextval
数组是对 next
数组的进一步优化,主要用于加快失配后的回溯过程。nextval
数组在失配时可以避免一些不必要的匹配操作,从而提高算法的效率。
2.3.1 写法1(不减1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public int[] getNextval(String s) { int n = s.length(); int[] nextval = new int[n]; int j = 0;
nextval[0] = -1;
for (int i = 1; i < n; i++) { while (j > 0 && s.charAt(i) != s.charAt(j + 1)) { j = nextval[j]; } if (s.charAt(i) == s.charAt(j + 1)) { j++; } nextval[i] = j; } return nextval; }
|
2.3.2 写法2(减1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public int[] getNextval(String s) { int n = s.length(); int[] nextval = new int[n]; int j = -1; nextval[0] = -1; for (int i = 1; i < n; i++) { while (j >= 0 && s.charAt(i) != s.charAt(j + 1)) j = nextval[j]; if (s.charAt(i) == s.charAt(j + 1)) j++;
if (i < n - 1 && s.charAt(i + 1) == s.charAt(j + 1)) nextval[i] = nextval[j]; else nextval[i] = j;
} return nextval; }
|