[LeetCode] 28. Implement strStr()

[LeetCode] 28. Implement strStr()


Implement strStr().

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.


实现strStr(h, n)函数,如果在h中能找到n的完全匹配字符串,则返回对应的第一个字符的下标,否则返回-1。

思路: 经典的字符串匹配问题,就用经典的KMP算法来做,复杂度O(m+n)。


KMP

硬爆算法是若两个字符串 h n 的当前字符 hi nj 不匹配, j 从头开始,导致了复杂度变成了O(m*n)。
KMP算法是首先在短字符串 n 中建立一个有匹配信息的next表,每当不匹配时, j 不是从头开始,而是直接跳到上一次已经匹配过的前缀开始,直接优化到了O(m+n)。

next表
next[i] = k表示了在字符串n中,从n[0-i]这一段字符串中,k长度的前缀与k长度的后缀完全匹配, next[0] = 0。
构造next表也可以理解为两个指针在短字符串n的匹配游走。

abaabaca
00112301


计算next表的算法:
k表示当前已匹配的数量,也可以认为是当前遍历字符串前缀的下标。
i表示是当前字符串的下标。

  • 如果n[k] == n[i], k++, next[i] = k, i++。
  • 否则,回溯k=next[i-1]直到n[k]==n[i]。
void getNextTable(string& needle, vector<int>& next) {
    int k = 0;
    int len = needle.length();
    for (int i=1; i<len; ++i) {
        while (k > 0 && needle[i] != needle[k]) {
            k = next[k-1];
        }
        if (needle[i] == needle[k]) {
            ++k;
        }
        next[i] = k;
    }
}

匹配的算法:
计数器c表示已匹配的长度。
当h[i]与n[j]不匹配时,j=next[j-1],回溯到n上已匹配的前缀位置开始比较,同时计数器c=next[j-1]。

if (haystack[i] == needle[j]) {
    ++matchNum;
    ++j;
    ++i;
} else {
    if (j == 0) {
        ++i;
    } else {
        matchNum = next[j-1];
        j = next[j-1];
    }
}

class Solution {
public:
    int strStr(string haystack, string needle) {
        int lenh = haystack.length();
        int lenn = needle.length();
        if (lenn == 0) {
            return 0;
        }
        vector<int> next(lenn, 0);
        getNextTable(needle, next);
        int matchNum = 0;
        int i=0, j = 0;
        while (i < lenh) {
            if (haystack[i] == needle[j]) {
                ++matchNum;
                ++j;
                ++i;
            } else {
                if (j == 0) {
                    ++i;
                } else {
                    matchNum = next[j-1];
                    j = next[j-1];
                }
            }
            if (matchNum == lenn) {
                return i-j;
            }
        }
        return -1;
    }

    void getNextTable(string& needle, vector<int>& next) {
        int k = 0;
        int len = needle.length();
        for (int i=1; i<len; ++i) {
            while (k > 0 && needle[i] != needle[k]) {
                k = next[k-1];
            }
            if (needle[i] == needle[k]) {
                ++k;
            }
            next[i] = k;
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值