題目地址:
https://leetcode.com/problems/implement-strstr/
給定兩個字符串,判斷第二個是否是第一個的子串,如果是則返回匹配的起始地址,否則返回。
法1:暴力法。直接枚舉所有的開始位置,依次做匹配,一旦匹配成功則返回起始點下標,如果一直未成功則返回。代碼如下:
public class Solution {
public int strStr(String s, String p) {
if (s == null || p == null) {
return -1;
}
if (p.isEmpty()) {
return 0;
}
// i後面要留足p的長度這麼多位置
for (int i = 0; i + p.length() - 1 < s.length(); i++) {
// 開始從p[0]開始匹配
int idx = 0;
while (idx < p.length()) {
if (s.charAt(i + idx) != p.charAt(idx)) {
break;
}
idx++;
}
// 匹配完了說明找到了子串,返回起始點下標
if (idx == p.length()) {
return i;
}
}
return -1;
}
}
時間複雜度,空間。
法2:KMP。KMP算法有一個next數組的概念,首先參考https://blog.csdn.net/qq_46105170/article/details/106168535,在未改進版本的KMP中,的next數組表示中最長的相等前後綴的長度,而在改進版本中,則表示當與不匹配的時候,裏下一個要與匹配的字符的下標。未改進版本的KMP中,這個下標取的是最長的相等前後綴的長度,利用這個信息去移動,可以在不錯過可能解的情況下,保證移動後和比較時,之前的字符已經全部相等,也就是不用再進行匹配了;但是它還可以利用一個信息,若移動後與對齊的那個字符仍然與相等,那麼肯定會出錯,還是得繼續向後移,改進的KMP算法就是將這個信息加入進去。首先,若,那麼下一個與對齊的字符變爲了,若還不等,則對齊的是,直到相等或者變爲爲止。如果我們已經知道了,那再次對齊就沒有意義,因爲還要取一次next。所以索性在一開始就”next到底“,杜絕的情況發生。代碼如下:
public class Solution {
public int strStr(String s, String p) {
if (s == null || p == null) {
return -1;
}
if (p.isEmpty()) {
return 0;
}
int i = 0, j = 0;
int[] next = buildNext(p);
while (i < s.length() && j < p.length()) {
if (j == -1 || s.charAt(i) == p.charAt(j)) {
i++;
j++;
} else {
j = next[j];
}
}
return j == p.length() ? i - j : -1;
}
private int[] buildNext(String p) {
int[] next = new int[p.length()];
int i = 0, j = next[0] = -1;
while (i < p.length() - 1) {
if (j == -1 || p.charAt(i) == p.charAt(j)) {
i++;
j++;
// 在未改進的KMP算法中,next[i]直接取j;
// 在改進的算法中需要判斷一下當前字符是否和p[j]相等,如果相等則還需要next一下
next[i] = p.charAt(i) == p.charAt(j) ? next[j] : j;
} else {
j = next[j];
}
}
return next;
}
}
時間複雜度,空間。