• 28. Implement strStr() KMP


    参考:https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/dong-tai-gui-hua-zhi-kmp-zi-fu-pi-pei-suan-fa

    问题:实现strstr,求是否为子串,若是,返回子串所在第一个字符的index,否则返回-1。

    Example 1:
    Input: haystack = "hello", needle = "ll"
    Output: 2
    
    Example 2:
    Input: haystack = "aaaaa", needle = "bba"
    Output: -1
    
    Clarification:
    What should we return when needle is an empty string? This is a great question to ask during an interview.
    For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf().
    
    Constraints:
    haystack and needle consist only of lowercase English characters.
    

      

    解法:KMP(字符串匹配算法)-> DP(动态规划)

    思想:首先有两个字符串:

    • 目标字符串 txt
    • 模式匹配串(子串)pat

    KMP算法的思想:只根据 pat 构建一个状态转移提示字典dp。

    根据dp,遍历txt,最后能使状态转移至最终状态,则匹配成功。

    1.构建dp:参照函数:KMP

    这里由于和状态迁移相关,我们很容易想到使用DP来构建辅助字典dp。

    • dp[j][c]:在当前状态 j 的情况下,遇到字符c,则需要迁移到的目标状态。
    • 状态转移:dp[j][c]=
      • 若c==pat[j],则向下一个状态迁移:j+1
      • 若c!=pat[j],则返回 影子状态 X

    这里,我们引入 影子状态X 的概念:

    • 该状态处于当前状态 j 的一个单位后滞状态。且0~X与0~j字符串拥有相同前缀。

    ⚠️  如何确定 影子状态X :

    由概念,我们可利用,在前面已经构建好的dp[][]来得知,X=dp[X][pat[j]]

    状态为前面的状态X的时候,遇到当前的字符 pat[j] 的迁移方法,

    • forward:继续向后迁移状态?相同前缀一起扩展一个字符。
    • backward:返回上一个影子状态?相同前缀不再存在。缩小相同前缀的长度。

    2.利用dp,匹配目标字符串txt

    使用 j 来记录当前状态,初始化为 0。

    使用 i 遍历txt,更新每次的状态 j = dp[j][txt[i]]

    如果 j = final状态,则返回 i-j+1 为子串开始index

    否则继续遍历,直到txt末尾,还未匹配则返回-1。

    代码参考:

     1 class Solution {
     2     //dp[j][c]:if we meet the char c when it is in status j, we should move to which status?
     3     //  case_1: c == pat[j]: dp[j][c] = j+1;
     4     //  other: dp[j][c] = dp[X][c] (X:the shadow status of j)
     5     //base case: dp[0][pat[0]] = 1 otherwise dp[0][other] = 0
     6     //how to fix X:
     7     //X is just one latter status after j,
     8     //and X has the same prefix string with j.
     9     //so we can exploit initialized dp[][] to update X.
    10     //X = dp[X][pat[j]]
    11     //has the same move(forward or backward) with preceding status j :dp[j][pat[j]]
    12 private:
    13     vector<vector<int>> dp;
    14 public:
    15     void KMP(string pat) { // DP
    16         int m = pat.length();
    17         dp.resize(m, vector<int>(256, 0));//the total number of ASCII is 256
    18         dp[0][pat[0]] = 1;
    19         int X=0;
    20         for(int j=1; j<m; j++) {
    21             for(int c=0; c<256; c++) {
    22                 if(c == pat[j]) {
    23                     dp[j][c] = j+1;
    24                 } else {
    25                     dp[j][c] = dp[X][c];
    26                 }
    27             }
    28             //update the shadow status X
    29             X = dp[X][pat[j]];
    30         }
    31     }
    32     int strStr(string haystack, string needle) {
    33         int m = needle.length(), n = haystack.length();
    34         if(m==0) return 0;
    35         KMP(needle);
    36         //use dp[][] to know how to transform in each status j
    37         int j = 0;
    38         for(int i=0; i<n; i++) {
    39             j = dp[j][haystack[i]];
    40             if(j==m) {
    41                 return i-j+1;
    42             }
    43         }
    44         return -1;
    45     }
    46 };
  • 相关阅读:
    POSIX共享内存
    jsp 传值jsp 数据库 乱码解决的攻略 全套
    遗传奥秘的伟大揭秘者:J.Watson
    js这些代码你都不会,你还有什么好说的!!!
    Android编程获取手机型号,本机电话号码,sdk版本号及firmware版本号号(即系统版本号号)
    广域网使用的常见设备
    门户系统整合sso cookie共享及显示用户信息
    cookie中的path与domain属性详解
    taotao用户登录(及登录成功后的回调url处理)
    taotao用户注册前台页面
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13656957.html
Copyright © 2020-2023  润新知