LintCode : 字符串查找

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;  
}

你可能感兴趣的:(LintCode)