代码随想录算法训练营第九天|28. 实现 strStr()|KMP算法

KMP算法之前看过一遍代码随想录,第一遍看的时候,勉强弄明白了KMP算法的基本原理。第二遍看之前已经忘记了(2个月之前看的)。

第二遍看的时候,捡起来很快。算法原理的理解上没有花太多时间,具体的实现细节还是会有想不明白的地方。

今天先记录一下KMP算法的具体实现的细节。

首先是next[]数组,也就是前缀表。需要先把前缀表求出来。前缀表不减1的步骤如下:

1.初始化。

int j = 0; 
next[0] = 0;

j为前缀末尾,

next[0]=0  对于前缀表不减1的实现方式来说就等于next[0]=0。

2.当前缀和后缀不相等的时候,j进行退回的操作。

for(int i = 1; i < s.size(); i++) { // 注意i从1开始
        while (j > 0 && s[i] != s[j]) { // 前后缀不相同了
            j = next[j-1]; // 向前回退
        }

while的条件里面,首先j>=0,是因为当j=0的时候说明已经是退回到底了,不可以再退回了。所以只有当j>0才可能退回。

其次就是s[i] != s[j]这个基本的退回条件。当前的前缀和后缀不相等时。

退回的操作是j = next[j-1]。j退回到j的前一个next数组值所指向的位置。因为next数组记录着j(包括j)之前的子串的相同前后缀的长度。(这里比较难想明白,先记住吧。)

3.当前缀和后缀相等的时候,j自增

for(int i = 1; i < s.size(); i++) {
            while (j > 0 && s[i] != s[j]) { // j要保证大于0,因为下面有取j-1作为数组下标的操作
                j = next[j - 1]; // 注意这里,是要找前一位的对应的回退位置了
            }
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }

回退和自增结束之后,此时i对应的next数组的值next[i] = j;

整体的求next数组的代码如下:

void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 0;
        for(int i = 1; i < s.size(); i++) {
            while (j > 0 && s[i] != s[j]) {
                j = next[j - 1];
            }
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }
    }

其中有个关于C++语法的问题是,这个函数的形参是const string& s,为什么不能是string s呢?

搜索到如下回答:

区别在于:
const 限定变量只读,
string& 的目的是引用,避免再复制一个std::string
所以说,const string s 需要一次复制操作,比较浪费,既然已经是只读了就直接用引用多好。

在讲引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。

主要是引用传递实际参数本身,不用拷贝,节约时间和空间。

关于strStr()函数本身,在haystack字符串中找到needel字符串的方法的原理和实现跟求next()数组的过程是一样的。当发生字符不匹配的时候,退回到j前一个next()数组值所指向的位置,如果匹配则j++。直到j等于needle的末尾。

函数如下所示:

    int strStr(string haystack, string needle) {
        if (needle.size() == 0) {
            return 0;
        }
        int next[needle.size()];
        getNext(next, needle);
        int j = 0;
        for (int i = 0; i < haystack.size(); i++) {
            while(j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == needle.size() ) {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值