问题描述:
●28.实现 strStr():给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。
●459.重复的子字符串:给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
解决方案:
对于第一个问题,我们可以使用双指针的方法来解决。具体来说,我们可以先判断 needle 是否为空,如果为空则返回 0。然后我们可以使用两个指针 i 和 j 分别指向 haystack 和 needle 的开头,然后开始遍历 haystack。如果 haystack[i] == needle[j],那么我们就将 i 和 j 都向后移动一位。如果遇到了 haystack[i] != needle[j] 的情况,那么我们就将 i 回溯到上一次匹配的位置的下一位,即 i = i - j + 1,然后将 j 归零,重新开始匹配。如果我们能够匹配到 needle 的结尾,那么就说明在 haystack 中找到了 needle,返回 i - j。如果遍历完了 haystack 还没有找到 needle,那么就返回 -1。
代码如下:
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) {
return 0;
}
int i = 0, j = 0;
while (i < haystack.length() && j < needle.length()) {
if (haystack.charAt(i) == needle.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j == needle.length()) {
return i - j;
} else {
return -1;
}
}
对于第二个问题,我们可以使用 KMP 算法来解决。KMP 算法的核心思想是利用已经匹配过的信息,避免在搜索过程中重复匹配。具体来说,我们可以先将原始字符串复制一遍,得到一个新的字符串 s。然后我们可以定义一个 next 数组,其中 next[i] 表示当匹配到 s[i] 时,如果匹配失败,下一次匹配应该从哪个位置开始。我们可以使用双指针 i 和 j 分别指向原始字符串和新字符串的开头,然后开始遍历新字符串。如果 s[i] == s[j],那么我们就将 i 和 j 都向后移动一位。如果遇到了 s[i] != s[j] 的情况,那么我们就将 j 回溯到 next[j] 的位置,然后继续匹配。如果我们能够匹配到新字符串的结尾,那么就说明原始字符串可以由一个子串重复多次构成,返回 true。如果遍历完了新字符串还没有找到匹配的子串,那么就返回 false。
代码如下:
public boolean repeatedSubstringPattern(String s) {
int n = s.length();
int[] next = new int[n + 1];
next[0] = -1;
int i = 0, j = -1;
while (i < n) {
if (j == -1 || s.charAt(i) == s.charAt(j)) {
i++;
j++;
next[i] = j;
} else {
j = next[j];
}
}
return next[n] > 0 && n % (n - next[n]) == 0;
}
在本次解决问题中,我们使用了双指针和 KMP 算法两种方法来解决字符串匹配的问题。双指针法的时间复杂度为 O(mn),其中 m 和 n 分别为 haystack 和 needle 的长度。KMP 算法的时间复杂度为 O(n),其中 n 为字符串的长度。由于 KMP 算法的时间复杂度比双指针法更优,所以在实际应用中,我们更倾向于使用 KMP 算法来解决字符串匹配的问题。