Implement strStr

Implement strStr().

Returns a pointer to the first occurrence of needle in haystack, or null if needle is not part of haystack.

思路:朴素算法和KMP,此外还有Karbin-ship算法。关于next的数组,只需要知道一点:求patten串i位置(包括自己)最大前缀子串的长度,这个长度其实就是将来i+1的位置失配之后,下一次j重新比较的位置。也可以理解为一个dp的过程

#include <iostream>
#include <string.h>
#include <assert.h>

using namespace std;

class Solution {
public:
    int * next(char * p){
        assert(p);
        int len = strlen(p);
        int * n = new int[len];
        n[0] = 0;
        int k = 0;
        
        for(int i = 1; i < len; i++){
            k = n[i-1];
            while(k > 0 && p[k] != p[i]){
                k = n[k-1];
            }
            if (p[k] == p[i]){
                n[i] = k + 1;
            }else{
                n[i] = 0;
            }
        }
        return n;
    }
    /**
        一下两种算法:1) if (j == size2) 统一放在for循环的里面,意味着找到满足匹配的就输出. 如果要求全部输出,那就需要在这里变形
                    2) &haystack[i - j] 返回的位置而言,朴素算法中,i和j是同步往前移动的,故最后返回的是 haystack[i - j]
                        但是KMP的算法中,i的循环是在for中,j的循环是在 return的前面,意味着i比j在当前的位置晚 1 步,所以最后输出的为止在haystack[i - j + 1]
                    3) 二者的for循环的边界都是在 i < size1,而j < size2 不需要判断,因为不可能超过的,j每次都往前最多走一步,而中间循环里面判断是否 j == size2 就决定退出
                    4) 关于复杂度的分析,朴素的算法最坏情况是 O(M*N)(i回退,每次最多回退j步).而KMP的复杂度是O(M+N),是因为j = n[j-1],能让j很快就退到0,而大部分情况是1步就回退到0的,总体而言,平均回退的步数不会超过2,总体是2*j.最后的复杂度是O(M+N)
    
    */
    char *strStrNormal(char *haystack, char *needle){
        assert(haystack && needle);
        int size1 = strlen(haystack);
        int size2 = strlen(needle);
    
if (size1 < size2){ return NULL; } int i = 0, j = 0; //去掉了 j < size2 的条件 while(i < size1){ if (haystack[i] == needle[j]){ i++; j++; //j往前面移动了j步,意味着i也是往前移动了i步,下次就要回退 j - 1 }else{ i = i - j + 1; //失配之后下一次匹配是 i+1的位置 j = 0; } if (j == size2){ //如果成功,那么j的位置肯定是在 needle.size(),难道不是吗? return &haystack[i - j]; //如果搞不清楚 是应该i -j or i - j +1,直接想想如果两个串一样的情况下,当然是i-j = 0 为位置 } } return NULL; } char *strStrKmp(char *haystack, char *needle) { assert(haystack && needle); int size1 = strlen(haystack); int size2 = strlen(needle); if (size1 < size2){ return NULL; } /**s |<- strlen(haystack) means end().相当于end()往左游走 strlen(needle)个元素,正好在needle起始的为止 XXXXXXXXXXX0 YYYY | last_index char * haystack = "ababc0000"; char * needle = "ababc"; return NULL, 有BUG,是因为j == size2应该在for循环里面,如果ok,就应该输出 */ int j = 0, i = 0; //获取特征数组 int * n = next(needle); for(; i < size1; i++){ //如果不等于,j就回退通过next数组,找到下一个合适比较的为止 直到相等或者j = 0 while(j > 0 && needle[j] != haystack[i]){ j = n[j - 1]; } //如果j退到0的为止. if (needle[j] == haystack[i]){ //相等就i++,j++,如果都不相等,那么i++,j回退到合适的为止 j++; } if (j == size2){ return &haystack[i - j + 1]; } } return NULL; } char *strStr(char *haystack, char *needle){ //return strStrNormal(haystack,needle); return strStrKmp(haystack,needle); } }; using namespace std; int main(int argc, char *argv[]) { char * haystack = "sdsdasdababcdsdedsdsdsdsdsds"; char * needle = "edsdsd"; Solution sol; cout << "result: " << sol.strStr(haystack,needle) << endl; return 0; }

 

posted @ 2013-06-20 01:52  一只会思考的猪  阅读(270)  评论(0编辑  收藏  举报