利用KMP算法解決LeetCode第28題:實現(xiàn)strStr()

簡介

  • KMP算法是一種字符串匹配算法冤留,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發(fā)現(xiàn)拷肌,因此人們稱它為克努特——莫里斯——普拉特操作(簡稱KMP算法)馋袜。KMP算法的關鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數(shù)以達到快速匹配的目的趁啸。具體實現(xiàn)就是實現(xiàn)一個next()函數(shù)强缘,函數(shù)本身包含了模式串的局部匹配信息。時間復雜度O(m+n)不傅。

算法分析

假設主串T用i指針遍歷旅掂,而模式串P用j指針遍歷。

和暴力法的區(qū)別

情況1:如果P[0]就不匹配了访娶,那么i指針指向下一位商虐,而j指針不變,這在暴力和KMP都一樣崖疤,不用多說秘车。
情況2:如果P的前幾個字符匹配的話,情況就有所不同劫哼。在暴力算法中叮趴,如果T[i] != P[j],i需要回溯到i-j+1的位置权烧,而j變?yōu)?疫向。而在KMP算法中,則是利用已經(jīng)部分匹配的有效信息豪嚎,i指針不回溯搔驼,通過修改j指針,讓模式串移動到有效的位置侈询。

重點和難點

KMP算法的重點和難點是如何求j指針在不匹配時的下一位置舌涨,這里將該位置設為k。這里引入一個next數(shù)組扔字,next[j]表示P[j]匹配失敗后囊嘉,j指針應指向的位置温技,即next[j] = k。

分析

為什么要求k值呢扭粱?k值是怎么來的舵鳞?

當T[i] != P[j]時(j>0),已知P[0 ... j-1] == T[i-j ... i-1]琢蛤,若P[0 ... k-1] == P[j-k ... j-1]蜓堕,
則P[0 ... k-1] == T[i-k ... i-1],此時只需將j指針移動到k博其,而i指針不需要移動套才,即可繼續(xù)進行比較。
所以此時問題轉化為求令P[0 ... k-1] == P[j-k ... j-1]的k的最大值慕淡,即P的前j個字符組成的子串的最長相同前綴后綴的長度(k)背伴。

next數(shù)組如何求

  • 特殊情況:next[0] = -1(此時j不用動,i向后移一位)峰髓;next[1] = 0(此時i不用動傻寂,j回溯到第0位);如果前j個字符都相同携兵,則next[j] = j-1疾掰。
  • 其他情況:next[j] = k,其中k為P[0 ... j-1]中最長相同前綴后綴的長度

實戰(zhàn):實現(xiàn)strStr()(LeetCode第28題)

題目描述

給定一個 haystack 字符串和一個 needle 字符串眉孩,在 haystack 字符串中找出 needle 字符串出現(xiàn)的第一個位置 (從0開始)个绍。如果不存在,則返回 -1浪汪。當 needle 是空字符串時我們應當返回 0 巴柿。這與C語言的 strstr() 以及 Java的 indexOf() 定義相符。

示例

示例1:

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

示例2:

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

代碼

    /**
     * 利用KMP算法求解
     *
     * 需要進行匹配的字符(即haystack字符串)死遭,稱為主串广恢,簡稱T
     * 模式(Pattern)字符串(即needle字符串),簡稱P
     *
     */
    private static int strStr_KMP(String haystack, String needle) {
        if (needle.equals("")) {
            return 0;
        }

        char [] T = haystack.toCharArray();
        char [] P = needle.toCharArray();
        int [] next = getNext(needle);
        int i = 0;
        int j = 0;

        while (i < haystack.length() && j < needle.length()) {
            if (j == -1 || T[i] == P[j]) {  //當j == -1時呀潭,i向后移動一位钉迷,j也要歸零
                i++;
                j++;
            } else {    //T[i] != P[j]時,i指針不用動钠署,j指針移動到相應的位置
                j = next[j];
            }
        }

        if (j == needle.length()) { //說明在主串T中找到了模式串P
            return i - j;
        } else {
            return -1;
        }
    }

    /**
     * 根據(jù)模式串P獲取next數(shù)組糠聪,next[j]表示P[j]匹配失敗后,j指針應指向的位置谐鼎。
     *
     * @param P 模式串
     * @return next數(shù)組
     */
    private static int [] getNext(String P) {
        int [] next = new int[P.length()];
        next[0] = -1;
        int k = -1;     //存儲當前next[j]對應的k值

        int j = 0;
        while (j < P.length()-1) {
            if (k == -1 || P.charAt(k) == P.charAt(j)) { //隱含條件P[0 ... k-1] == P[j-k ... j-1]
                //當k == -1時舰蟆,next[j++] = 0,例如next[1] = 0,或者前j字符沒有相同前綴后綴時也為0身害。
                //當P[k] == P[j]時味悄,由于P[0 ... k-1] == P[j-k ... j-1],則此時P[0 ... k] == P[j-k ... j]塌鸯,所以此時next[j+1] = k+1
                next[++j] = ++k;
            } else {
                //當P[k] != P[j]時侍瑟,next[j+1]必定小于k,此時可以縮小k的值(最小小到-1)
                k = next[k];
            }
        }

        return next;
    }

參考

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末丙猬,一起剝皮案震驚了整個濱河市涨颜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淮悼,老刑警劉巖咐低,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揽思,死亡現(xiàn)場離奇詭異袜腥,居然都是意外死亡,警方通過查閱死者的電腦和手機钉汗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門羹令,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人损痰,你說我怎么就攤上這事福侈。” “怎么了卢未?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵肪凛,是天一觀的道長。 經(jīng)常有香客問我辽社,道長伟墙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任滴铅,我火速辦了婚禮戳葵,結果婚禮上,老公的妹妹穿的比我還像新娘汉匙。我一直安慰自己拱烁,他們只是感情好,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布噩翠。 她就那樣靜靜地躺著戏自,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伤锚。 梳的紋絲不亂的頭發(fā)上擅笔,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音,去河邊找鬼剂娄。 笑死蠢涝,一個胖子當著我的面吹牛,可吹牛的內容都是我干的阅懦。 我是一名探鬼主播和二,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼耳胎!你這毒婦竟也來了惯吕?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤怕午,失蹤者是張志新(化名)和其女友劉穎废登,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郁惜,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡堡距,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了兆蕉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羽戒。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖虎韵,靈堂內的尸體忽然破棺而出易稠,到底是詐尸還是另有隱情,我是刑警寧澤包蓝,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布驶社,位于F島的核電站,受9級特大地震影響测萎,放射性物質發(fā)生泄漏亡电。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一绳泉、第九天 我趴在偏房一處隱蔽的房頂上張望逊抡。 院中可真熱鬧,春花似錦零酪、人聲如沸冒嫡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孝凌。三九已至,卻和暖如春月腋,著一層夾襖步出監(jiān)牢的瞬間蟀架,已是汗流浹背瓣赂。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留片拍,地道東北人煌集。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像捌省,于是被迫代替她去往敵國和親苫纤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容

  • 字符串匹配KMP算法詳解 1. 引言 以前看過很多次KMP算法纲缓,一直覺得很有用卷拘,但都沒有搞明白,一方面是網(wǎng)上很少有...
    張晨輝Allen閱讀 2,411評論 0 3
  • 數(shù)據(jù)結構與算法--KMP算法查找子字符串 部分內容和圖片來自這三篇文章: 這篇文章祝高、這篇文章栗弟、還有這篇他們寫得非常...
    sunhaiyu閱讀 1,743評論 1 21
  • title: 串的模式匹配算法之kmptags: 數(shù)據(jù)結構與算法之美author: 辰砂tj 1.引言 首先我們需...
    tojian閱讀 975評論 0 0
  • 引言 字符串匹配一直是計算機科學領域研究和應用的熱門領域,算法的改進研究一直是一個十分困難的課題工闺。作為字符串匹配中...
    潮汐行者閱讀 1,650評論 2 6
  • 生活在2016-12-03凌晨乍赫,替熟睡的娃爹值夜的我,整理各個寫了一半的草稿 乖乖每次出去玩斤寂,看到小哥哥小姐姐的滑...
    大雨不愁閱讀 228評論 0 0