2

Implement strStr()

最新更新:https://yanjia.me/zh/2019/02/...

Implement strStr().

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

暴力法

复杂度

时间 O(N^2) 空间 O(1)

思路

本题有很多高级算法可以在O(N)时间内解决问题,然而这已经超出面试的范畴。本题在面试中出现的作用就是考察基本的编程素养,以及边界条件的考虑。我们用暴力法即可。

代码

public class Solution {
    public int strStr(String haystack, String needle) {
        int start = 0;
        // 如果剩下的字母不够needle长度就停止遍历
        while(start <= haystack.length() - needle.length()){
            int i1 = start, i2 = 0;
            while(i2 < needle.length() && haystack.charAt(i1)==needle.charAt(i2)){
                i1++;
                i2++;
            }
            if(i2 == needle.length()) return start;
            start++;
        }
        return -1;
    }
}

KMP算法

复杂度

时间 O(N+M) 空间 O(M)

思路

KMP算法是较为高级的算法。它使用一个next数组,这个数组记录了模式串needle自身的前缀和后缀的重复情况。同样是双指针进行匹配,当失配时可以根据这个数组找到应该将模式串向后位移多少位,避免一些重复的比较。具体的解法这里有两篇文章比较好,一篇是详细讲解KMP算法

如果看完对产生next数组的方法还不太明白,还有一篇是讲解next数组怎么得到的

代码

public class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length() == 0){
            return 0;
        }
        int[] next = new int[needle.length()];
        // 得到next数组
        getNextArr(next, needle);
        // i是匹配串haystack的指针,j是模式串needle的指针
        int i = 0, j = 0;
        // 双指针开始匹配
        while(i < haystack.length() && j < needle.length()){
            // 如果j=-1意味着刚刚失配过,下标+1后,下一轮就可以开始匹配各自的第一个了
            // 如果指向的字母相同,则下一轮匹配各自的下一个
            if(j == -1 || haystack.charAt(i) == needle.charAt(j)){
                i++;
                j++;
            // 如果失配,则将更新j为next[j]
            } else {
                j = next[j];
            }
        }
        return j == needle.length() ? i - j : -1;
    }
    
    private void getNextArr(int[] next, String needle){
        // k是前缀中相同部分的末尾,同时也是相同部分的长度,因为长度等于k-0。
        // j是后缀的末尾,即后缀相同部分的末尾 
        int k = -1, j = 0;
        next[0] = -1;
        while(j < needle.length() - 1){
            // 如果k=-1,说明刚刚失配了,则重新开始计算前缀和后缀相同的长度
            // 如果两个字符相等,则在上次前缀和后缀相同的长度加1就行了
            if (k == -1 || needle.charAt(j) == needle.charAt(k)){
                k++;
                j++;
                next[j] = k;
            } else {
            // 否则,前缀长度缩短为next[k]
                k = next[k];
            }
        }
    }
}

ethannnli
858 声望360 粉丝