day09 ●28. 实现 strStr() ●459.重复的子字符串

96 阅读2分钟

问题描述:

●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 算法来解决字符串匹配的问题。