算法之暴力破解和kmp算法 判斷A字符串是否包含B字符串

咱們都知道java中有封裝好的方法,用來比較A字符串是否包含B字符串java

以下代碼,contains,用法是 str1.contains(str2), 這個布爾型返回,存在返回true,不存在返回false算法

還有indexOf,用法和contains一致,返回值是int,存在則返回對應的位置,注意位置從0開始的,不存在返回-1數組

public class Test { public static void main(String[] args) { String source = "abacaabacabacabaabb"; String pattern = "abacab"; System.out.println(source.contains(pattern) ); //true System.out.println(source.indexOf(pattern) ); //5  } }

這兩個方法的具體實現,是在java.lang包中,最終類String下函數

 public boolean contains(CharSequence s) { return indexOf(s.toString()) > -1; }
contains其實調用了indexOf
public int indexOf(String str) { return indexOf(str, 0); }
public int indexOf(String str, int fromIndex) { return indexOf(value, 0, value.length, str.value, 0, str.value.length, fromIndex); }
static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } if (fromIndex < 0) { fromIndex = 0; } if (targetCount == 0) { return fromIndex; } char first = target[targetOffset]; int max = sourceOffset + (sourceCount - targetCount); for (int i = sourceOffset + fromIndex; i <= max; i++) { /* Look for first character. */
            if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */
            if (i <= max) { int j = i + 1; int end = j + targetCount - 1; for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); if (j == end) { /* Found whole string. */
                    return i - sourceOffset; } } } return -1; }

 

若是你沒有去看java中自帶的實現,要你本身寫方法實現呢優化

這就涉及到了算法:算法就是你的思路=======spa

第一步: 先構思一下思路,我要怎麼去比較;通常人的思路是:rest

我拿後者的第一個字符,去看前者中是否含有,若是米有,必定不匹配;code

我拿後者的第一個字符,去看前者中是否含有,若是前者中含有,繼續查看,第二個字符是否和長串中接下來的一個字符相等blog

相等,繼續向下匹配(以下圖一)遞歸

不相等,從新用後者的第一個字符再和長字符串接下來一位進行比較

何謂接下來一位呢【假設abcdefgh和ddd,第一次比配到長字符串的第四位相等,第二次和長字符串的第5位開始比較,以下圖二】

 

public class Force { /** * 暴力匹配 *  時間複雜度爲O(n*m);n爲主串長度,m爲模式串長度    算法的基本思想:       從主串的起始位置(或指定位置)開始與模式串的第一個字符比較,若相等,則繼續逐個比較後續字符; 不然從主串的下一個字符再從新和模式串的字符比較。 依次類推,直到模式串成功匹配,返回主串中第一次出現模式串字符的位置,或者模式串匹配不成功,返回不成功,實際中可將返回值設置爲int,不成功返回-1,成功返回0; * @param source * @param pattern * @return
     */
    public static String bruteForceStringMatch(String source, String pattern) { int slen = source.length(); int plen = pattern.length(); char[] s = source.toCharArray(); char[] p = pattern.toCharArray(); int i = 0; int j = 0; if (slen < plen) return "你瞧瞧主串長度小於模式串,怎麼可能啊,匹配失敗"; // 若是主串長度小於模式串,直接返回-1,匹配失敗
        else { while (i < slen && j < plen) { if (s[i] == p[j]) // 若是i,j位置上的字符匹配成功就繼續向後匹配
 { System.out.println(i+ "的值是"+ s[i] ); System.out.println(j + "的值是"+ p[j]); ++i; ++j; } else { System.out.println("我是else下的" + i + "的值是"+ s[i] ); System.out.println("我是else下的" + j + "的值是"+ p[j]); i = i - (j - 1); // i回溯到主串上一次開始匹配下一個位置的地方
                    j = 0; // j重置,模式串從開始再次進行匹配
 } } if (j == plen) // 匹配成功
                return "位置是"+(i+1 - j); else
                return "匹配失敗"; // 匹配失敗
 } } }

查看匹配結果: 

 這是暴力破解,abcdeddd和ddd,在ddd的第0位和abcdeddd的第3位匹配後,繼續比較下一位,發現不匹配了,從新將ddd的第0位和

 kmp的思路以下:

KMP算法
  KMP算法是D.E.Knuth、V.R.Pratt和J.H.Morris同時發現,因此命名爲KMP算法。
  此算法能夠在O(n+m)的時間數量級上完成串的模式匹配。
  主要就是改進了暴力匹配中i回溯的操做,KMP算法中當一趟匹配過程當中出現字符比較不等時,
不直接回溯i,而是利用已經獲得的「部分匹配」的結果將模式串向右移動(j-next[k])的距離。

import java.util.Arrays; public class kmp { /** * KMP算法   KMP算法是D.E.Knuth、V.R.Pratt和J.H.Morris同時發現,因此命名爲KMP算法。   此算法能夠在O(n+m)的時間數量級上完成串的模式匹配。   主要就是改進了暴力匹配中i回溯的操做,KMP算法中當一趟匹配過程當中出現字符比較不等時, 不直接回溯i,而是利用已經獲得的「部分匹配」的結果將模式串向右移動(j-next[k])的距離。 * @param source * @param pattern * @return
     */
    public static String kmpStringMatch(String source, String pattern) { int i = 0; int j = 0; char[] s = source.toCharArray(); char[] p = pattern.toCharArray(); int slen = s.length; int plen = p.length; int[] next = getNext(p); while(i < slen && j < plen) { if(j == -1 || s[i] == p[j]) { ++i; ++j; } else { //若是j != -1且當前字符匹配失敗,則令i不變, //j = next[j],即讓pattern模式串右移j - next[j]個單位
                j = next[j]; } } if(j == plen) return "位置是"+(i+1 - j); else
            return "匹配失敗"; // 匹配失敗
 } /** * 關於next[k]數組的計算引出的兩種辦法,一種是遞歸,一種對遞歸優化,第一種對應的就是KMP算法,第二種就是優化的KMP算法。 next函數值僅取決於模式串自己而和主串無關。 有不少講next函數值計算辦法的資料,在此我想用一種直觀的比較容易理解的辦法來表達。 舉個栗子:如今有一個模式串abab 模式串的各個字串  前綴 後綴 最大公共元素長度 a null null 0 ab a b 0 aba a,ab a,ba 1 abab a,ab,aba b,ab,bab 2 * @param p * @return
     */
    private static int[] getNext(char[] p) { /** * 已知next[j] = k, 利用遞歸的思想求出next[j+1]的值 * 1.若是p[j] = p[k],則next[j+1] = next[k] + 1; * 2.若是p[j] != p[k],則令k = next[k],若是此時p[j] == p[k],則next[j+1] = k+1 * 若是不相等,則繼續遞歸前綴索引,令k=next[k],繼續判斷,直至k=-1(即k=next[0])或者p[j]=p[k]爲止 */
        int plen = p.length; int[] next = new int[plen]; System.out.println("next函數值:" + Arrays.toString(next)); int k = -1; int j = 0; next[0] = -1;                //這裏採用-1作標識
        while(j < plen -1) { if(k == -1 || p[j] == p[k]) { ++k; ++j; next[j] = k; } else { k = next[k]; } } System.out.println("next函數值:" + Arrays.toString(next)); return next; } }
相關文章
相關標籤/搜索