【LeetCode刷题日记】28.strStr

 

在2018的最后一个工作日,刷到leetcode上的一道关于字符串类型的题,题目是这样的:

--------------------------------------------------------------------------------------------------------------------------------------

实现 strStr() 函数。

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

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2

示例 2:

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

说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

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

-----------------------------------------------------------------------------------------------------------------------------------------

看到题目的第一反应,这不是indexOf就搞定了嘛,抱着皮一下很开心的原则,我输入了以下答案:

return haystack.indexOf(needle);

果然通过,并且查看运行时间只有4ms,emmmmm,那我要自己写一个来看看,于是又有了以下的答案:

    /*
    1)先判断needel是否为空字符串;
    2)然后再比较这两个串是否完全相等
    3)从haystack的开头开始取出和needle大小相当的字串进行比较,找到第一个相等的则返回当前index
    4)上述条件都不符合则表示needel不是haystack的字串,返回-1
     */
    public int strStr(String haystack,String needle){
        if(needle.length()==0){
            return 0;
        }
        if(haystack.equals(needle)){
            return 0;
        }
        for (int i = 0;i<=haystack.length()-needle.length();i++){
            if(haystack.substring(i,i+needle.length()).equals(needle)){
                return i;
            }
        }
        return -1;
    }

But,我写的这个东西,它的运行时间是7ms,emmmmm,在强烈好奇心的驱使下,我准备看看indexOf是怎么做的,以前都是“哎这个好用,哎那个也好用”,从2019年起我要做一个知其所以然的好青年,嘻嘻。

【LeetCode刷题日记】28.strStr_第1张图片

打开String.java类,找到indexOf(String str),是这样的:

     /**
     *  返回字符串中字串str第一次出现的位置。
     *  @param str 是需要寻找的字串
     *  @return 字串第一次出现的位置,如果字串没有出现,则返回-1
     * 
     */
    public int indexOf(String str) {
        return indexOf(str, 0);
    }

这个函数return了indexOf(str,0),就是indexOf方法的重载:

int indexOf(String str, int fromIndex):从指定索引处寻找子串出现的第一个位置。

那我们就接着看indexOf(String str, int fromIndex)的源码是怎么做的:

  /**
    
     * 从指定索引处开始寻找,返回子串在字符串中第一次出现的位置
     * @param   str         子串
     * @param   fromIndex   指定开始寻找的位置 
     * @return  从指定位置处开始寻找,返回子串第一次出现的位置,如果找不到,则返回-1
     */
    public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }

emmmmm,又是调用了一个重载的indexOf函数,那就接着往下找呗:

  /**
     * 这是String 和 StringBuffer 用来进行搜索的代码,源是要搜索的字符数组(character array)
     * 目标是被搜索的字符串
     * @param   source        被搜索的字符数组(源)
     * @param   sourceOffset  字符串源的偏移
     * @param   sourceCount   字符串源的长度
     * @param   target        被搜索的字符数组(目标)
     * @param   targetOffset  目标字符串的偏移
     * @param   targetCount   目标字符串的长度
     * @param   fromIndex     开始进行搜索的索引
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {//如果开始的索引大于源字符串的长度
            //如果目标字符串长度为0,则返回源字符串的长度,否则返回-1
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {//如果起始索引小于0,则设置起始索引为0,从源的开始处进行查找
            fromIndex = 0;
        }
        if (targetCount == 0) {
            //如果目标字符串长度为0(空串),则返回指定的索引,空串当然在哪个位置都是匹配的嘛
            return fromIndex;
        }

        char first = target[targetOffset];//取目标的偏移量位置的字符
        int max = sourceOffset + (sourceCount - targetCount);//计算最多需要遍历到源的位置
        
        // i 初值取源偏移+指定索引,表示从源的哪个位置开始匹配
        // i 应当取到max位置为止
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {//将目标的第一个字符与源进行匹配
                //在max范围内去寻找第一个字符匹配的位置,
                //如果没有,这个for就结束了,返回最后的-1表示没找到
                while (++i <= max && source[i] != first);
            }

            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                //j 表示源与目标第一个字符匹配位置的下一个位置
                int j = i + 1;
                //end 表示匹配停止的位置,也就是从j往后 targetCount-1个位置
                //(target Count-1表示剩下需要匹配的字符 
                int end = j + targetCount - 1;
                //k 表示从target开始匹配的位置
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
                //找到了子串
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }

到这里已经明白了,有一点就是,在这里其实都是操作字符数组进行的,所以在调用String的这些方法时,其实是转换成数组在进行操作。这和我自己写的那个其实有一点相似,都是按位置比较子串,但我还是用了人家的substring方法(我懒,要不要待会再看看substring的源码?LOL)

那我们根据indexOf的思想来写一个看看:

public int mystrStr(String haystack,String needle){
        char[] source = haystack.toCharArray();
        char[] target = needle.toCharArray();
        int sourceCount = source.length;
        int targetCount = target.length;

        if(targetCount == 0){
            return 0;
        }
        char first = target[0];
        int max = sourceCount-targetCount;
        for(int i = 0;i<=max;i++){
            if(source[i] != first){
                while(++i<=max && source[i] != first);
            }
            if(i<=max){
                int j = i+1;
                int end = j + (targetCount-1);
                for(int k = 1;j

山寨版登场,其实也没差多少,然后我们去提交看看:

【LeetCode刷题日记】28.strStr_第2张图片

都差不多嘛,好的我佛了。但是我比第一个7ms的时候更有知识了哦嘻嘻。

你可能感兴趣的:(Leetcode)