随想录一期 day9 KMP算法 [28.找出字符串中第一个字符的匹配项]

Source

28.找出字符串中第一个字符的匹配项

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例 1: 输入: haystack = "hello", needle = "ll" 输出: 2

示例 2: 输入: haystack = "aaaaa", needle = "bba" 输出: -1

思路

  • 滑动窗口+双指针
  • 步骤1:找到第一个字符串匹配的位置
  • 步骤2:从字符串匹配的首字符开始,双指针移动
  • 步骤3:模式串的指针指向模式串的长度,则完成匹配
  • 步骤4:第一个字符匹配后,遇见冲突,i指针回退到i-j-1位置

复杂度

  • 时间 O(n*m)
  • 空间 O(1)
暴力求解
class Solution {
    
      
    public int strStr(String haystack, String needle) {
    
      
        //模式串为空,返回0
        int n = haystack.length(), m = needle.length();
        if (m == 0) {
    
      
            return 0 ;
        }
        if(n < m){
    
      
            return -1;
        }
        int i = 0 ,j = 0;
        while (i < (n - m + 1)) {
    
      
            //判断两个字符串的首字符是否相同
            while(i<n && haystack.charAt(i) != needle.charAt(j)){
    
      
                i++;
            }
            if(i == n){
    
      
                return -1 ;
            }
            //文本串和模式串首字符相同
            while (i < n && j < m && haystack.charAt(i) == needle.charAt(j)) {
    
      
                i++;j++;
            }
            //j 等于模式串长度时,说明匹配结束,返回开始字符小标
            if(j == m){
    
      
                return i- j ;
            }else{
    
      
                //出现未匹配字符,i还原到匹配前的位置
                i -= j -1;
                j = 0 ;
            }
        }
        return -1;
    }
}

KMP算法求解
  • 思路

    • 求模式串的前缀表

    • 找到文本串中匹配到的第一个字符的问题(字符不相等需要一直寻找,用到while),回退到前一位对应的下标的位置

    • 字符串相同则指针同时向后移动

    • 模式串指针等于长度时,说明完全匹配,返回i=m+1

  • 时间复杂度O(m+n)

  • 空间复杂度O(m)

class Solution {
    
      
    public int strStr(String haystack, String needle) {
    
      
        //模式串为空,返回0
        int n = haystack.length(), m = needle.length();
        if (m == 0) {
    
      
            return 0 ;
        }
        if(n < m){
    
      
            return -1;
        }
        int[] next = new int[m];
        getNext(next,needle);
        //字符串前缀的最后一个字符的位置
        int j = 0;
        for (int i = 0; i < n; i++) {
    
      
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
    
      
                j = next[j-1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
    
      
                j++;
            }
            if(j == m){
    
      
                return i-m +1;
            }
        }
        return -1;
    }

    public void getNext(int[] next, String s) {
    
      
        int j = 0 ;
        next[0] = 0 ;
        for (int i = 1; i < s.length(); i++) {
    
      
            //1、字符不等,回退j
            while(j>0 && s.charAt(i) != s.charAt(j)){
    
      
                j = next[j-1];
            }
            if(s.charAt(i) == s.charAt(j)){
    
      
                j++;
            }
            next[i] =j;
        }
    }
}

解答成功:
	执行耗时:0 ms,击败了100.00% 的Java用户
	内存消耗:39.3 MB,击败了69.87% 的Java用户

总结

  • 参考资料:https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html