LintCode : 字符串查找

来源:互联网 发布:淘宝中的花呗怎么关闭 编辑:程序博客网 时间:2024/06/05 04:44

LintCode : 字符串查找

题目

对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。

样例

如果 source = “source” 和 target = “target”,返回 -1。
如果 source = “abcdabcdefg” 和 target = “bcd”,返回 1。

思路

O(n^2):
朴素的字符串匹配方法,从模式串第一个字符开始匹配,中途发现不匹配的字符,则放弃此次匹配,接着从第二个字符开始匹配。知道发现匹配的字符串,返回结果。O(n^2)的算法貌似是可以AC的,但是我们发现可以有复杂度更低的方法去完成这道题,这就是我们经典的KMP算法了。

O(n):
KMP算法运行过程中每趟匹配过程中出现字符比较不等时,不回溯主指针i,利用已得到的“部分匹配”结果将模式向右滑动尽可能远的一段距离,继续进行比较。

s1 s2 s3…si-j+1 si-j+2…si-2 si-1 si si+1             ‖       ‖       ‖    ‖   ≠                 p1      p2  …  pj-2 pj-1 pj pj+1                         ‖        ‖                         p1  …  pk-1  pk pk+1

① “p1p2…pk-1” = “si-k+1si-k+2…si-1”

②“pj-k+1pj-k+2…pj-1” = “si-k+1si-k+2…si-1”(部分匹配)

③ “p1p2…pk-1” = “pj-k+1pj-k+2…pj-1” (真子串)

为此,定义next[j]函数,表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需重新和主串中该字符进行比较的字符串的位置。

next[j] = max { k | 1 < k < j , 且”p1…pk-1” = “pj-k+1…pj-1”
( 这里我设置 next[0] = -1, next[1] = 0 )

求解next

p1 p2…pj-k+1…pj-1 pj pj+1   next[j]=k             ‖          ‖   ≠             p1 …  pk-1 pk  pk+1   next[k]=k’                 p1 ……  pk’ pk’+1  next[k’]=k”                    p1… pk’’ pk’’+1 next[k’’]=k’’’

也就是说比较当前所求的值得字符与前一个字符是否相同,如果相同则前值+1,如果不相同则递归的比较next[next[j - 1]]的字符与前一个字符是否相同。

代码

int get_len(const char *str) {    if(str == NULL)        return -1;    int i = 0;    while(str[i] != '\0') {        i++;    }    return i;}void get_next(int *next, const char *source) {    next[0] = -1;    next[1] = 0;    int i = 1;    int j = 1;    while(i < get_len(source)) {        if(source[i] == source[next[j]]) {            i++;            next[i] = next[j] + 1;            j = i;        }        else if(next[j] == -1) {            i++;            next[i] = 0;            j = i;        }        else {            j = next[j];        }    }}int strStr(const char *source, const char *target) {    int sl = get_len(source);    int tl = get_len(target);    if(sl < tl)        return -1;    if(tl == 0 && sl != -1) {        return 0;    }    if(sl == -1 || tl == -1)        return -1;    int *next = new int[tl + 1];    get_next(next, target);    int i = 0, j = 0;    while(i < sl && j < tl) {        if(j == -1 || source[i] == target[j]) {            i++;            j++;        }        else {            j = next[j];        }    }    if(j == tl)        return i - j;    else         return -1;  }
0 0
原创粉丝点击