【刷题笔记】LeetCode_28:实现strStr()_简单(C)

题目:实现strStr()

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例 1:

输入: haystack = “hello”, needle = “ll”
输出: 2

示例 2:

输入: haystack = “aaaaa”, needle = “bba”
输出: -1

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

这道题刚看的时候以为很简单,没想到坑还挺多。。自己写的代码如下,也不知道对不对,反正超时了。。。。

int strStr(char * haystack, char * needle){

    char first;

    int i = 0;
    int j = 0;
    int k = 1;
    int length = strlen(haystack);
    int num = strlen(needle);
    int flag = 1;
    int judge = 0;
    int address;
    
    if(needle[0] == '\0') return 0;
    if(length < num) return -1;
    
    
        first = needle[0];

        while(haystack[i] != '\0')
        {
            if(haystack[i] == first)
            {
                address = i;
                for(j=i+1; k<num; j++)//比较完num长度就ok
                {
                    if(haystack[j] != needle[k])//这一组不是needle
                    {
                        flag = 0;
                        break;
                    }
                    k++;
                }
                if(!flag) //说明break过,可能haystack里没有needle也可能在下一个num长度有
                {
                    i = j-1;//防止下一个num长度有needle,接着扫描,所以更新i
                    k = 1;//恢复k=1
                    flag = 1;//更新flag
                }
                else judge = 1;//没break过说明找到了needle
            }   
            i++; //如果judge,说明已经找到了,再i++会比正确的多1
        }

    if(!judge) return -1;
    else return address;
    
    

}

刚开始的思路是:先在haystack里挨个扫描,寻找needle的首字符,如果找不到,则直接返回-1;如果找得到,记录此时的位置,接着扫描,接下来的字符如果和needle接下来的字符相同则返回位置,如果有一个不同就break出循环,返回-1。

但是!!这个思路有漏洞!!例如:

输入:haystack = “missiissip”,needle = “issip”
输出:5

这个用例让我发现我这个思路不太对,因为needle的首字符是“i”,初次出现的位置为1,但是扫描发现后面的字符和needle对不上,这时候就会break出来返回-1,这是不对的!!因为后面还有一段,还要接着扫描!!

所以我又设置了judge变量,一旦break出来的时候更新i,j,flag的值接着扫描,看接下来haystack里未扫描的字符有没有符合needle的。

但是!!又出了问题!!!最外层的while循环最后有一个i++的操作,用来控制找到first的位置。但是如果有judge=1的情况,即找到first后,后面的字符串与needle匹配,不需要break出来更新值接着扫描,那么这时候的i加了1,address也相应多加了一。所以我把i++改成了:if(!judge) i++,但是。。超时了。。。。所以我只能去看别人的代码了。。。

以下是看了别人的代码之后写出的AC代码,不过n^2的复杂度真的慢的一p,回头再看看大神比较快的算法吧。。

int strStr(char * haystack, char * needle){

    int length = strlen(haystack);

    int num = strlen(needle);

    int flag = 0;

    int i,j;

    if(needle[0] == '\0') return 0;
    if(length <num) return -1;

    for(i=0; i<length; i++)
    {
        flag = 0;
        for(j=0; j<num; j++)
        {
            if(haystack[i+j] != needle[j])
            {
                flag = 1;
                break;
            }
        }
        if(!flag) return i;
    }
    return -1;

}

这个双层循环的暴力解法就是外层循环控制haystack,内层循环控制needle,外层先从i=0开始,内层从j=0开始,如果haystack[i+j]与needle[j]不相同就会break出来,然后i++,直到找到与needle第一个字符相同的位置,以此类推。要注意的是:

1.flag的值要记得更新!!因为有可能出现前面missiissip那个用例的情况,需要进入一次以上的内层for循环。

2.if(!flag) return i; 这句要写在内层循环结束后,外层循环内。因为内层循环结束后,如果flag=0,说明已经匹配成功,直接return;如果flag=1,说明还需要进一步进行扫描匹配操作,如果把这句判断写在外层循环外,那是得不到正确答案的。因为外层循环结束的条件是haystack已经全部扫描结束,flag的值就不好说了。。

3.haystack[i+j]的理解。因为内层循环每一次进入,j都会初始化为0,即needle每一次都是从头比较,省去了我第一次的代码每一次都要手动更新,而如果没找到haystack里与needle第一个字符相同的字符位置,是无法执行内层循环的,因为一进去就会break出来。找到了后执行内层循环,那么i+j的值会随着j++增加,相当于就是在haystack里的首字符出现位置开始一个一个的与needle字符串比较,省去了我前面“i=j-1”的愚蠢的更新操作。

你可能感兴趣的:(刷题笔记,leetcode,字符串)