leetcode:Implement strStr() & KMP 算法

leetcode:Implement strStr() & KMP 算法


问题描述

实现strstr(),即字符串匹配。使用KMP算法解决。但是其实暴力求解也跟KMP算法的速度是相差无几的,因为目标串太短了


KMP算法与自动机


在编译原理的书上看见KMP算法的一种解释,将目的串转换成一个自动机,初始状态为0,假如目的串为helloworld,那么状态0接受'h'转换为状态1,状态1接受'e'转换为状态2,依次类推。
KMP算法的关键就是在某个状态x接收到不匹配的字符时,找到应该返回的状态,而不是每次都返回状态0(若返回状态0,则目标串指针向前走一步)。以一个数组保存状态1到状态n收到错误字符时应该返回的位置,如果达到状态n,则表示字符串已经被接收,所以最后一个状态不存在所谓的"接收到错误字符"。


vector<int> next(needle.size(), 0);
int t = 0;
for(int i = 2; i < needle.size(); ++i){
    while(t > 0 && needle[t] != needle[i - 1]){
        t = next[t];
    }
    if(needle[t] == needle[i - 1]){
        next[i] = ++t;
    }else{
        next[i] = 0;
    }
}

代码中以next[x]表示状态x接收到错误字符时应该返回的状态(该状态必须在x之 前,如果继续返回x状态,则有可能造成死循环,所以next[1] = 0 )并且当达到状态n时,表示字符串已经匹配,所以不需要求next[n]

代码中的t表示上一个状态接收错误字符时会返回的状态,i从2开始,所以t的初始值为next[1],也就是0。同时,t也可以表示上一个状态收到错误字符串时,满足如下条件的,最长的子串s的长度:

  1. s是目标串的真前缀
  2. s同时是已经匹配部分的真后缀

也可以理解为发生不匹配时,目标串应该向后走的步数。并且next[i]最多只会比next[i-1]大1,否则next[i-1]就不是最长的符合条件的s的长度。

为什么while循环里要有t=next[t]?执行到while循环入口时,已经到达了状态i,即已经接受了i个字符,也是说在到达状态i-1时,自动机以为自己接受到了正确的字符,所以到达了状态i,但是这个字符是不对的,因为继续收下去会出错,所以问题就变成了我们回到了状态状态next[i-1],也就是t的初始值,然后问题就变成了我们在状态t,并且收到了字符needle[i - 1],如果这个第i个字符是正确的,即needle[t] == needle[i-1]那么跳出while,同时next[i] = ++t,如果这个字符是错误的,继续往回找。因为s是已经匹配部分的真后缀,所以每次回溯都会是need[t]与next[i-1]比较。最后t==0时跳出循环,证明如果在状态i收到错误字符就只能重新匹配,源串指针向后滑动。即next[i] = 0,同时此时t的值也为0(跳出的条件就是t=0嘛)

完整AC代码如下:

class Solution {
public:
    int strStr(string haystack, string needle) {
        vector<int> next(needle.size(), 0);
        int t = 0;
        for(int i = 1; i < needle.size(); ++i){
            while(t > 0 && needle[t] != needle[i - 1]){
                t = next[t];
            }
            if(needle[t] == needle[i - 1]){
                next[i] = ++t;
            }else{
                next[i] = 0;
            }
        }

        int state = 0;
        int pos = 0;
        while(state != needle.size        () && pos != haystack.size()){
            if(haystack[pos] == needle[state]){
                ++state;
                ++pos;
            }else if(!(state = next[state]) && haystack[pos] != needle[state]){
                ++pos;
            }
        }
        if(state == needle.size()){
            return pos - state;
        }else{
            return -1;
        }
    }
};

posted on 2015-07-02 19:05  远近闻名的学渣  阅读(224)  评论(0)    收藏  举报

导航