LeetCode之實現IndexOf()

LeetCode之實現IndexOf()

聲明

博客中關於算法截圖,來自七月算法PPT,bilibili地址
博文涉及代碼地址:碼雲

原題

在這裏插入圖片描述

解題思路

暴力法

    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) {
            return 0;
        }
        int needStart = 0;
        //for 循環每個位置開始匹配
        for (int i = 0; i + needStart < haystack.length(); i++) {
            //從首位開始比較
            while (i + needStart < haystack.length() && needStart < needle.length()) {
                if (haystack.charAt(i + needStart) == needle.charAt(needStart)) {
                    //匹配,則比較位置向後一位
                    needStart++;
                } else {
                    //不匹配,比較位置歸零,跳出循環,i向後移動一位
                    needStart = 0;
                    break;
                }
            }
            //如果比較位置超過了,匹配字符長度,則是已經匹配到
            if (needStart >= needle.length()) {
                return i;
            }
        }
        //沒有匹配到返回-1
        return -1;
    }

在這裏插入圖片描述

KMP算法

算法說明

  1. kmb算法解釋
  2. kmb核心算法 next()
    看完想法:next()函數作用,就是求前綴和後綴是否重複部分,有重複的時候,在平移的時候要考慮

算法實現

    /**
     * @param haystack 源字符串
     * @param needle   匹配字符串
     * @return int
     * @throws
     * @author Eric
     * @date 2019/5/22
     **/
    public int kmpStrStr(String haystack, String needle) {
        if (needle.length() == 0) {
            return 0;
        }
        int[] next=next(needle);
        int p=0;
        int i=0;
        while(i<haystack.length()){
            if(p == -1||haystack.charAt(i)==needle.charAt(p)){
                ++p;
                ++i;
            }else{
                p=next[p];
            }
            if(p>=needle.length()){
                return i-p;
            }
        }
        return -1;
    }
 /**
     * <p>
     * 求出 匹配字符串得next函數
     *                 0  j=0
     * next()=     Max{k|0<k<j   , P1 P2 ...Pk=Pj-k+1 Pj-k+2}
     *                 1        其他情況
     * </p>
     *
     * @param needle 1
     * @return int[]
     * @throws
     * @author Eric
     * @date 2019/5/22
     **/
    public int[] next(String needle) {
        int[] arr = new int[needle.length()+1];
        arr[0]=-1;
        for (int i = 0; i < needle.length(); i++) {
            int k=i;
            if ( i== 0) {
                arr[i+1] = 0;
            } else if (0 < k && k <= i) {
                while (k > 0) {
                    if (needle.substring(0, k).equals(needle.substring(i+1 - k , i+1))) {
                        arr[i+1] = k;
                        break;
                    }
                    k--;
                }
            }
        }
        return arr;
    }

總結: 結果並不是太理想,我都不好意思貼leetcode運行結果了,消耗的空間和時間都非常的多,空間消耗比較多,主要再subString()方法會重複new對象,這裏可以優化,但是就算我優化了,也是需要遍歷,時間複雜度又提升
疑問:KMP真的有那麼優秀,再我看來,KMP真的不如BF算法,假設沒有不考慮求next數組的時間複雜度,KMP確實M+N的複雜度,但是求next數組應該是M*M(非專業,大概計算,不會推到)級別的
最後求大佬指點,哪裏不對,哪裏還有可以優化

自己優化next函數

  1. 不使用substring方法,自己寫方法實現同樣的效果,結果空間複雜度確實降下來了,時間複雜度依舊沒降下來,測試差不多
 /**
     * <p>
     * 優化後的 求next數組 方法
     * </p>
     *
     * @param needle 1
     * @return int[]
     * @throws
     * @author Eric
     * @date 2019/5/23
     **/
    public int[] smartNext(String needle) {
        int[] arr = new int[needle.length() + 1];
        arr[0] = -1;
        for (int i = 0; i < needle.length(); i++) {
            if (i == 0) {
                arr[i + 1] = 0;
            } else {
                arr[i + 1] = getK(needle, i);
            }
        }
        return arr;
    }
    /**
     * <p>
     *     求next 函數 最大k值
     * </p>
     * @author Eric
     * @date 2019/5/23
     * @param needle    字符串
     * @param i         字符串 偏移位置
     * @return int
     * @throws
     **/
    private int getK(String needle, int i) {
        for(int k=i;k>0;k--){
            for(int j=1;j<=k;j++){
                if(needle.charAt(k-j)!=needle.charAt(i+1-j)){
                    break;
                }
                if(j==k){
                    return k;
                }
            }
        }
        return 0;
    }

百度到next優化


    /**
     * <p>
     *     百度到最優 next 求解
     * </p>
     * @author Eric
     * @date 2019/5/23
     * @param  needle 字符串
     * @return int[]
     * @throws
     **/
    public int [] fastNext(String needle){
        int len = needle.length();
        int [] next=new int[len+1];
        next[0]=-1;
        if(needle.length()==0){
            return next;
        }
        //初始化
        next[1]=0;
        for(int i=1,k=0;i<len;i++) {
            //這個while是最關鍵的部分
            while(k>0 && needle.charAt(k)!=needle.charAt(i)){
                k=next[k];
            }
            //等價於  k=next[next[i-1]-1]
            //等號右邊的k起的只是下標的作用
            if(needle.charAt(k)==needle.charAt(i)){
                //相等就+1
                k++;
            }
            //賦值
            next[i+1]=k;
        }
        return next;
    }

三種next 時間測試結果

在這裏插入圖片描述

  1. 這裏就多解釋,百度的到時候複雜度是O(N) 級別的

BF算法

算法說明

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
感受: 個人覺得BF算法比KMP算法好理解多了,KMP最難理解就是next函數

算法實現

 /**
     * <p>
     *     BF 算法實現的 indexOf() 方法
     *     壞字符串概率
     *     移動量=匹配字符串出現壞樹的時候 匹配字符串的下標-源字符串(壞字符串)在被匹配字符串再次出現的下表
     *     A A A A A A becsdsddadadsd      A 壞字符串
     *               |
     *     b A b d d a
     *     偏移量=5-1       4
     * </p>
     * @author Eric
     * @date 2019/5/22
     * @param hayStack   源字符串
     * @param needle     匹配字符串
     * @return int       匹配的初始位置
     * @throws
     **/
    public int bfIndexOf(String hayStack, String needle) {
        if (needle.length() == 0) {
            return 0;
        }
        //初始化長度
        int hLen=hayStack.length()-1;
        //初始化長度
        int nLen=needle.length()-1;
        //i  源字符串 偏移量
        int i=nLen;
        // 匹配字符串偏移量
        int index=nLen;
        while(i<=hLen){
            // 源字符串向後匹配 偏移量
            int yd=i;
            while(index>=0){
                if(hayStack.charAt(yd)==needle.charAt(index)){
                    //匹配成功 則向後匹配
                    yd-- ;
                    index--;
                    if(index<0){
                        return i-nLen;
                    }
                }else{
                    //匹配失敗則是壞字符串,匹配壞字符串是否有匹配的
                    int match=-1;
                    for(int j=index-1;j>=0;j--){
                        if(hayStack.charAt(yd)==needle.charAt(j)){
                            match=j;
                            break;
                        }
                    }
                    i+=index-match;
                    index=nLen;
                    break;
                }
            }
        }
        return index<0?i-nLen:-1;
    }

leetcode執行結果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章