KMP算法 字符串匹配

解题思路

总算理解KMP算法
前缀表求得是最大的公共前后缀长度 最长size-1, e.g siis 不是求回文串 所以不能动态规划
siis ==> [0,0 ,1 ] sii vs iis ,
前缀是指string[0:size-1]
后缀是指string[1:size]

无论是求前缀表还是比较模式串与目标字符串, 都需要用到“回退”
写代码时候 最后结合一个例子来写 写出框架

代码

class Solution {
public:
    int strStr(string haystack, string needle) 
    {

        if(needle.empty()) return 0;
        
        //首先 O(m) 求出next 数组 
        // 前缀和后缀最大相同
        //  j i
        //a a b a a f
        std::vector<int> next(needle.size(),0);
        int j=0;
        for(int i=1;i<needle.size(); i++)
        { 
           //回退
           while( j>0 && needle[i] != needle[j] ) j= next[j-1];

           if(needle[i] == needle[j]  ) j++;
           next[i] =j;
        }

        // for(auto t:next) std::cout << t << " ";
        // std::cout << std::endl;
        
//   aabaa b aafa
//   aabaa f
//   -------
//   aabaa b aafa
//   aa b aaf   //确保 needle[j] = hay[i]
//   --------
//   aabaabaa f a
//   aabaa f ok   needle_idx = needle.size
//   else -------
//   aabaabaa f a
//   aabaa e
//   ---------
//   aabaabaa f a
//   aa b aae
//   ----------
//   aabaabaafa  when hay end, needle_idx != size  return -1
//   aa b aae
//O(n) 根据前缀表进行匹配
    j=0;
    for(int i=0;i<haystack.size();i++)
    {
        //回退 确保 needle[j] = hay[i]
        std::cout << i << " " << j << std::endl;
        while( j>0 && needle[j]!= haystack[i] )
        {
            j = next[j-1];
        }
        if(needle[j]== haystack[i])    j++;
    
        if(j== needle.size() ) return i- needle.size()+1;
    }

    //e.g 
//     "aabaabaafa"
// "aabaaf"
// output:
// 0 0
// 1 1
// 2 2
// 3 3
// 4 4
// 5 5
// 6 3
// 7 4
// 8 5

    return -1;

    }
};

暴力解法代码,顺便回顾下动态规划

class Solution {
public:
    int strStr(string haystack, string needle) {
//动态规划解法 参考  https://leetcode-cn.com/problems/implement-strstr/solution/dong-tai-gui-hua-jie-fa-by-xqlsq/
// dp[i][j]  表示 needle[..j] 在 hay[...i]出现的位置  
// 显然 
// if hay[i] = hay[j] , dp[i][j]= dp[i-1][j-1]
// 举例验证 ,注意初始化时候 空needle 在 haystack中是0, 其他情况 -1 
//      l  l 
//   0 -1 -1 
// h 0 -1 -1   
// e 0 -1 -1
// l 0 2  -1  
// l 0 3  2
// o 0 -1 -1
// //by exe
// 0 -1 -1 
// 0 -1 -1 
// 0 -1 -1 
// 0 2 -1 
// 0 3 2 
// 0 -1 -1 

//* 关键是needle[0] 首次出现位置移到要初始化为i-1
//offset 法 , needle[j] hay[i] ==> dp[i+1][j+1] 
//如果不用二维dp 则必须从右向左遍历 
 
std::vector<std::vector<int>> dp(haystack.size()+1, std::vector<int>(needle.size()+1,0 ));

for(int j=1;j<=needle.size();j++)  dp[0][j] =-1;


for(int i=0;i<haystack.size();i++)
{
    #if 0 
    //从左到右遍历 会超时 
    for(int j=0;j< needle.size();j++ ) 
    {
       if(haystack[i] == needle[j] ) 
       {
           if(j>0) dp[i+1][j+1]  = dp[i][j];
           else dp[i+1][j+1] = i;
       }else
       {
           dp[i+1][j+1] = -1;
       }

       //here detect
       if(j== needle.size() -1 && dp[i+1][j+1] != -1 )  return dp[i+1][j+1];

    }

    #endif 
    // //从右到左遍历会超时  

     for(int j=needle.size()-1;j>=0;j-- ) 
    {
       if(haystack[i] == needle[j] ) 
       {
           if(j>0) dp[i+1][j+1]  = dp[i][j];
           else dp[i+1][j+1] = i;
       }else
       {
           dp[i+1][j+1] = -1;
       }

       //here detect
       if(j== needle.size() -1 && dp[i+1][j+1] != -1 )  return dp[i+1][j+1];

    }

}

// for(auto vec: dp) 
// {
//     for(auto t: vec ) std::cout << t << " ";
//     std::cout << std::endl;
// }


if(haystack.empty() || needle.empty() ) return dp[haystack.size()][needle.size()];
return -1;



    }
};

题目描述

  1. 实现 strStr()
    实现 strStr() 函数。

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

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

示例 1:

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

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

输入:haystack = "", needle = ""
输出:0

提示:

0 <= haystack.length, needle.length <= 5 * 104
haystack 和 needle 仅由小写英文字符组成

posted @ 2021-05-31 10:54  boyang987  阅读(33)  评论(0编辑  收藏  举报