随想录一刷Day09——字符串

Day09_字符串

KMP来啦

找出字符串中第一个匹配项的下标

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

下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面从新匹配就可以了。
所以前缀表具有告诉我们当前位置匹配失败,跳到之前已经匹配过的地方的能力。

KMP写法一:next数组第一个记录为0,相当于记录了前缀表

class Solution {
public:
    void getNext(string &needle, int *next) {
        int j = 0;
        int needle_len = needle.length();
        next[0] = 0;
        for (int i = 1; i < needle_len; ++i) {
            while (j > 0 && needle[i] != needle[j]) { // 如果没匹配上,就一直往前找
                j = next[j - 1]; // 当前这一位没有匹配上,应该回退到上一位记录的相等前缀的后一位
            }
            if (needle[i] == needle[j]) { // 如果匹配上了,就将相等前后缀的长度+1
                j++;
            }
            next[i] = j;
        }
    }

    int strStr(string haystack, string needle) {
        int haystack_len = haystack.length();
        int needle_len = needle.length();
        int next[needle_len];
        getNext(needle, next);
        int j = 0;
        for (int i = 0; i < haystack_len; ++i) {
            while (j > 0 && haystack[i] != needle[j]) { // 如果没匹配上,就一直往前找能匹配上的前缀
                j = next[j - 1]; // 当前这一位没有匹配上,应该回退到上一位记录的相等前缀的后一位
            }
            if (haystack[i] == needle[j]) { // 如果匹配上了,就继续向后匹配
                j++;
            }
            if (j == needle_len) { // 返回匹配到的模式串在文本串中出现的第一个位置
                return (i - j + 1);
            }
        }
        return -1;
    }
};

KMP写法二:next数组第一个记录为-1,即前缀表统一减一实现。

直接得到next表示前缀表的形式,匹配不上的时候要去前一个点找前缀位置
前缀表统一减一后,匹配不上的位置next中对应的就是应该去找的前缀的位置

class Solution {
public:
    void getNext(string &needle, int *next) {
        int j = -1;
        int needle_len = needle.length();
        next[0] = j;
        for (int i = 1; i < needle_len; i++) {
            while (j >= 0 && needle[i] != needle[j + 1]) { // 由于j从-1开始,所以j+1才能对应到数组的下标上
                j = next[j];
            }
            if (needle[i] == needle[j + 1]) {
                j++;
            }
            next[i] = j;
        }
    }

    int strStr(string haystack, string needle) {
        int haystack_len = haystack.length();
        int needle_len = needle.length();
        int next[needle_len];
        getNext(needle, next);
        int j = -1;
        for (int i = 0; i < haystack_len; ++i) {
            while (j >= 0 && haystack[i] != needle[j + 1]) {
                j = next[j];
            }
            if (haystack[i] == needle[j + 1]) {
                j++;
            }
            if (j + 1 == needle_len) {
                return (i - needle_len + 1); // 注意此时j+1才等于needle_len注意返回制别错了
            }
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值