LeetCode String 28 Implement strStr()

28. Implement strStr()

Implement strStr().

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

Example 1:
Input: haystack = “hello”, needle = “ll”
Output: 2

Example 2:
Input: haystack = “aaaaa”, needle = “bba”
Output: -1

Clarification:
What should we return when needle is an empty string? This is a great question to ask during an interview.

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf().

solution 1: substring

利用java自带的String的substring method.

    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) return 0;
        int flag = 1;
        for (int i = 0;i < haystack.length()-needle.length() + 1; i++) {
            if (haystack.substring(i,i+needle.length()).equals(needle))
                return i;
        }
        return -1;
    }

solution 2: KMP substring algorithm

KMP算法可以在 O ( n ) O(n) O(n)时间内完成substring的查找
其主要思想就是利用brute force方法中一个字符一个字符匹配时忽略的信息。
首先一个重要的概念就是prefix和suffix(前缀,后缀)以及前后缀数组。

前后缀数组table[i]是指代表substring中从起始到index i,前缀和后缀相同的最大长度。以substring needle = “d s a t d s d t”为例子,needle就是需要匹配的substring。

     index =   0 1 2 3 4 5 6 7 
     needle = [d s a t d s d t]
     table  = [0 0 0 0 1 2 1 0]

在index为4的地方出现第一个前后缀相同的,‘d’,所以最大长度为1;
在index为5的地方相同前后缀都是"ds",所以最大长度为2;
在index为6的地方相同前后缀都是"d",所以最大长度为1;
计算前后缀数组的代码如下图所示。

        int[] table = new int[needle.length()];
        for (int i = 0; i < table.length;i++) {
            table[i] = 0;
        }
        int i = 0, j = 1;
        while (j < needle.length()) {
            if (needle.charAt(j) == needle.charAt(i)) {
                table[j] = table[j-1] + 1;
                i++;
            } else if (needle.charAt(j) == needle.charAt(0)) {
                table[j] = 1;
                i = 1;
            } else table[j] = 0;
            j++;
        }

接下来讨论这个前后缀数组table究竟有什么作用:
同样以needle = “d s a t d s d t”为例子,假设匹配时,匹配到最后一个d时,发现和string不相同

	 ....dsatdsw.....
needle : dsatdsdt

此时我们就得到了下面的信息:dsatds匹配到了且前后缀数组中’s’对应的值为2,说明最大相同前后缀长度为2。那么我i们此时就没有必要从string中d下一个字符开始匹配,我们只需要从不匹配的位置’w’处开始往后匹配,因为w前面的
"ds"一定可以和needle的前缀匹配,由于needle中前后缀相同的性质,所以只需要从string中的‘w’与needle中index为2的字符比较就可以,这个"2"就来自于前后缀数组table。

一个更直观的例子
A=”abaabaabbabaaabaabbabaab”
B=”abaabbabaab”
table = [0 0 1 1 2 0 1 2 3 4 5]

最开始匹配时发现到index = 5时匹配不上,于是回到table查table[5-1] = 2
A=”abaabaabbabaaabaabbabaab”
B=”abaabbabaab”
进行下一次匹配
A=abaabaabbabaaabaabbabaab
\\\\\\B=abaabbabaab

    public int strStr2(String haystack, String needle) {
        if (needle.length() == 0) return 0;
        // first build the suffix-prefix table of the needle
        // define two pointers
        // table[i] represents the maximum length of
        // the suffix that is also a prefix before i.
        // for example, needle = [d s a t d s d t]
        //               table = [0 0 0 0 1 2 1 0]
        int[] table = new int[needle.length()];
        for (int i = 0; i < table.length;i++) {
            table[i] = 0;
        }
        int i = 0, j = 1;
        while (j < needle.length()) {
            if (needle.charAt(j) == needle.charAt(i)) {
                table[j] = table[j-1] + 1;
                i++;
            } else if (needle.charAt(j) == needle.charAt(0)) {
                table[j] = 1;
                i = 1;
            } else table[j] = 0;
            j++;
        }
        int t = 0;
        int start = 0;
        int k = 0;
        while (k < haystack.length()) {
            if (haystack.charAt(k) == needle.charAt(t)) {
                t++;
                k++;
            } else if (t > 0) {
                start = k - table[t-1];
                t = table[t-1];
            } else start = ++k;
            if (t == needle.length()) return start;
        }
        return -1;
    }

上面的代码中需要注意的是如何更新pointer t,k以及start。还有一点要注意的是while loop中需要特别解决t=0的情况,此时就需要pointer 看向后一位,start update为k,然后从头开始匹配,不可以使用table数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值