KMP算法之解決字符串匹配的問(wèn)題

應(yīng)用場(chǎng)景-字符串匹配問(wèn)題

字符串匹配問(wèn)題::
有一個(gè)字符串 str1= ""你好的乘客就變成了威威成本即可奧爾加本次選舉二點(diǎn)五啦"",和一個(gè)子串 str2="本次選"
現(xiàn)在要判斷 str1 是否含有 str2, 如果存在篮绿,就返回第一次出現(xiàn)的位置, 如果沒(méi)有孵延,則返回-1

解決思路

暴力匹配算法

如果用暴力匹配的思路,并假設(shè)現(xiàn)在str1匹配到 i 位置亲配,子串str2匹配到 j 位置尘应,則有:

如果當(dāng)前字符匹配成功(即str1[i] == str2[j]),則i++吼虎,j++菩收,繼續(xù)匹配下一個(gè)字符

如果失配(即str1[i]! = str2[j]),令i = i - (j - 1)鲸睛,j = 0。相當(dāng)于每次匹配失敗時(shí)坡贺,i 回溯官辈,j 被置為0。

用暴力方法解決的話就會(huì)有大量的回溯遍坟,每次只移動(dòng)一位拳亿,若是不匹配,移動(dòng)到下一位接著判斷愿伴,浪費(fèi)了大量的時(shí)間肺魁。(不可行!)

暴力匹配算法實(shí)現(xiàn).

public class ViolenceMatch {

    public static void main(String[] args) {
        String str1 = "暴力破解算法之任意字符串圍毆文憑的么快二u我圍毆的打錯(cuò)了";
        String str2 = "圍毆的";
        int index = violenceMatch(str1, str2);
        System.out.println("index=" + index);
    }

    // 暴力匹配算法實(shí)現(xiàn)
    public static int violenceMatch(String str1, String str2) {

        char[] s1 = str1.toCharArray();
        char[] s2 = str2.toCharArray();

        int s1len = s1.length;
        int s2len = s2.length;

        int i = 0; // i索引指向s1
        int j = 0; // j索引指向s2
        while (i < s1len && j < s2len) {// 保證匹配時(shí),不越界
            if(s1[i] == s2[j]){
                i++;
                j++;
            } else {
                i = i-(j-1);
                j=0;
            }
        }

        if(j==s2len){
            return i-j;
        } else {
            return -1;
        }
    }
}

結(jié)果

image

KMP算法解決

KMP算法介紹

KMP是一個(gè)解決模式串在文本串是否出現(xiàn)過(guò)隔节,如果出現(xiàn)過(guò)鹅经,最早出現(xiàn)的位置的經(jīng)典算法

Knuth-Morris-Pratt 字符串查找算法,簡(jiǎn)稱為 “KMP算法”怎诫,常用于在一個(gè)文本串S內(nèi)查找一個(gè)模式串P 的出現(xiàn)位置瘾晃,這個(gè)算法由Donald Knuth、Vaughan Pratt幻妓、James H.
Morris三人于1977年聯(lián)合發(fā)表蹦误,故取這3人的姓氏命名此算法.

KMP方法算法就利用之前判斷過(guò)信息,通過(guò)一個(gè)next數(shù)組肉津,保存模式串中前后最長(zhǎng)公共子序列的長(zhǎng)度强胰,每次回溯時(shí),通過(guò)next數(shù)組找到妹沙,前面匹配過(guò)的位置偶洋,省去了大量的計(jì)算時(shí)間

參考資料:https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html

image

image
image
image
image

獲取部分匹配值的代碼實(shí)現(xiàn)如下:

//獲取到一個(gè)字符串(子串) 的部分匹配值表
    public static  int[] kmpNext(String dest) {
        //創(chuàng)建一個(gè)next 數(shù)組保存部分匹配值
        int[] next = new int[dest.length()];
        next[0] = 0; //如果字符串是長(zhǎng)度為1 部分匹配值就是0
        for(int i = 1, j = 0; i < dest.length(); i++) {
            //當(dāng)dest.charAt(i) != dest.charAt(j) ,我們需要從next[j-1]獲取新的j
            //直到我們發(fā)現(xiàn) 有  dest.charAt(i) == dest.charAt(j)成立才退出
            //這時(shí)kmp算法的核心點(diǎn)
            while(j > 0 && dest.charAt(i) != dest.charAt(j)) {
                j = next[j-1];
            }
            
            //當(dāng)dest.charAt(i) == dest.charAt(j) 滿足時(shí)初烘,部分匹配值就是+1
            if(dest.charAt(i) == dest.charAt(j)) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }
}

核心代碼實(shí)現(xiàn):

public class KMPAlgorithm {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str1 = "BBC ABCDAB ABCDABCDABDE";
        String str2 = "ABCDABD";
        //String str2 = "BBC";
        
        int[] next = kmpNext("ABCDABD"); //[0, 1, 2, 0]
        System.out.println("next=" + Arrays.toString(next));

        int index = kmpSearch(str1, str2, next);
        System.out.println("index=" + index); // 15了

    }
    
    //寫(xiě)出我們的kmp搜索算法
    /**
     * 
     * @param str1 源字符串
     * @param str2 子串
     * @param next 部分匹配表, 是子串對(duì)應(yīng)的部分匹配表
     * @return 如果是-1就是沒(méi)有匹配到涡真,否則返回第一個(gè)匹配的位置
     */
    public static int kmpSearch(String str1, String str2, int[] next) {
        
        //遍歷 
        for(int i = 0, j = 0; i < str1.length(); i++) {
            
            //需要處理 str1.charAt(i) 分俯!= str2.charAt(j), 去調(diào)整j的大小
            //KMP算法核心點(diǎn), 可以驗(yàn)證...
            while( j > 0 && str1.charAt(i) != str2.charAt(j)) {
                j = next[j-1];
            }
            
            if(str1.charAt(i) == str2.charAt(j)) {
                j++;
            }           
            if(j == str2.length()) {//找到了 // j = 3 i 
                return i - j + 1;
            }
        }
        return  -1;
    }

    //獲取到一個(gè)字符串(子串) 的部分匹配值表
    public static  int[] kmpNext(String dest) {
        //創(chuàng)建一個(gè)next 數(shù)組保存部分匹配值
        int[] next = new int[dest.length()];
        next[0] = 0; //如果字符串是長(zhǎng)度為1 部分匹配值就是0
        for(int i = 1, j = 0; i < dest.length(); i++) {
            //當(dāng)dest.charAt(i) != dest.charAt(j) ,我們需要從next[j-1]獲取新的j
            //直到我們發(fā)現(xiàn) 有  dest.charAt(i) == dest.charAt(j)成立才退出
            //這時(shí)kmp算法的核心點(diǎn)
            while(j > 0 && dest.charAt(i) != dest.charAt(j)) {
                j = next[j-1];
            }
            
            //當(dāng)dest.charAt(i) == dest.charAt(j) 滿足時(shí)哆料,部分匹配值就是+1
            if(dest.charAt(i) == dest.charAt(j)) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }
}

結(jié)果:

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缸剪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子东亦,更是在濱河造成了極大的恐慌杏节,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典阵,死亡現(xiàn)場(chǎng)離奇詭異奋渔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)壮啊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)嫉鲸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人歹啼,你說(shuō)我怎么就攤上這事玄渗。” “怎么了狸眼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵藤树,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拓萌,道長(zhǎng)岁钓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上倦踢,老公的妹妹穿的比我還像新娘。我一直安慰自己囚霸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布激才。 她就那樣靜靜地躺著拓型,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瘸恼。 梳的紋絲不亂的頭發(fā)上劣挫,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音东帅,去河邊找鬼压固。 笑死,一個(gè)胖子當(dāng)著我的面吹牛靠闭,可吹牛的內(nèi)容都是我干的帐我。 我是一名探鬼主播坎炼,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拦键!你這毒婦竟也來(lái)了谣光?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤芬为,失蹤者是張志新(化名)和其女友劉穎萄金,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體媚朦,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氧敢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了询张。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孙乖。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖份氧,靈堂內(nèi)的尸體忽然破棺而出的圆,到底是詐尸還是另有隱情,我是刑警寧澤半火,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站季俩,受9級(jí)特大地震影響钮糖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酌住,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一店归、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酪我,春花似錦消痛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至欺矫,卻和暖如春纱新,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背穆趴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工脸爱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人未妹。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓簿废,卻偏偏與公主長(zhǎng)得像空入,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子族檬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 字符串匹配KMP算法詳解 1. 引言 以前看過(guò)很多次KMP算法歪赢,一直覺(jué)得很有用,但都沒(méi)有搞明白导梆,一方面是網(wǎng)上很少有...
    張晨輝Allen閱讀 2,390評(píng)論 0 3
  • title: 串的模式匹配算法之kmptags: 數(shù)據(jù)結(jié)構(gòu)與算法之美author: 辰砂tj 1.引言 首先我們需...
    tojian閱讀 961評(píng)論 0 0
  • KMP 算法(Knuth-Morris-Pratt 算法)是一個(gè)著名的字符串匹配算法轨淌,效率很高,但是確實(shí)有點(diǎn)復(fù)雜看尼。...
    labuladong2閱讀 654評(píng)論 0 3
  • 引言 字符串匹配一直是計(jì)算機(jī)科學(xué)領(lǐng)域研究和應(yīng)用的熱門(mén)領(lǐng)域递鹉,算法的改進(jìn)研究一直是一個(gè)十分困難的課題。作為字符串匹配中...
    潮汐行者閱讀 1,629評(píng)論 2 6
  • 忽然想起以前很愛(ài)梁靜茹的歌,她結(jié)婚生子后淡出人們的視線許久狰域,诚彼看見(jiàn)她發(fā)微博,照片上抱著寶寶幸福地笑兆览。 她寧愿舍棄燈...
    MickeySuper閱讀 653評(píng)論 0 3