国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。?!

這篇具有很好參考價值的文章主要介紹了【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。?!。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


以下是能用KMP求解的算法題,KMP是用于字符串匹配的經(jīng)典算法【至今沒學(xué)懂………啊啊啊】

28. 找出字符串中第一個匹配項的下標

題目鏈接:28. 找出字符串中第一個匹配項的下標
題目內(nèi)容:
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。?!,力扣刷題,leetcode,算法,字符串匹配,KMP算法
題意還是很好理解的,要在字符串haystack中查找一個完整的needle,即字符串匹配。

暴力求解

暴力求解就是用兩層循環(huán):haystack從第i個字符開始,needle從第一個字符開始j = 0,之后依次判斷needle[j]和haystack[j+i]是否相等。如果不相等,說明haystack中從第i位開始的子串和needle是不匹配的。之后j要回溯到j(luò) = 0,i向后移動一位。代碼實現(xiàn)(C++):

class Solution {
public:
    int strStr(string haystack, string needle) {
    	//haystack下標最大值
        int n = haystack.size() - needle.size();
        //外層是haystack從下標i開始和needle逐字符比較
        for(int i = 0 ; i <= n; i++){
            int j = 0;
            //needle從j=0開始
            while( j < needle.size()){
            	//如果有相等就退出循環(huán),開啟下一輪
                if(haystack[j+i] != needle[j])
                    break;
                j++;
            }
            //如果是遍歷完needle都與從i開始的子串相同,就找到了
            if(j == needle.size())
                return i;
        }
        return -1;
    }
};

KMP

暴力求解中,如果當前的needle[j]和haystack[j+i]不匹配,needle中j會回退到0,haystack中i+j回退到i+1,這里是可以優(yōu)化的,KMP就是為了減少這樣的回溯。
KMP是用于求解字符串匹配的算法,在當前needle[j]和haystack[j+i]不匹配時,能夠快速找到j(luò)應(yīng)該移動到的位置,而不是直接回溯到開頭。比如下面圖中s[i]和p[j]不匹配后,由于p[j]前面的子串的前綴ab和后綴ab相同,因此j不需要回溯到0,是移動到abc中c的位置,繼續(xù)和s[i]比較。
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。?!,力扣刷題,leetcode,算法,字符串匹配,KMP算法
KMP中一個重點是最長相同前后綴長度什么是前綴:一個字符串從第一個字符開始的,不包括最后一個字符的子串;什么是后綴:一個字符串中從最后一個字符開始的,不包括第一個字符的子串。
最長相同前后綴長度,就是一個字符串中相同的前后綴里面,最長的一組的長度。比如下圖里對于ababa這個字符串,相同前后綴有兩組,但是我們需要最長那組的長度。因為字符串匹配過程中,S[i]和P[j]不匹配時,j是要根據(jù)P[j]前面子串的前后綴長度來回退的,選擇最長前后綴能夠保證不遺漏答案。
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。?!,力扣刷題,leetcode,算法,字符串匹配,KMP算法
KMP算法需要求模式串P的next數(shù)組,實際上這個next數(shù)組記錄的就是P所有從第一個字符開始的子串的最長相同前后綴的長度:next[i]表示下標0到下標i這段子串的,最長相同前后綴的長度。假設(shè)有next[i-1]=m,那么next[i] <= next[i-1]+1,其中取等需要P[next[i-1]] == P[i]?!疽驗閚ext[i-1]里面存的是長度,當作下標的時候就是最長相同前后綴里面那個前綴后面一個字符;而P[i]就是P[i-1]最長相同前后綴的后綴的后后面一個字符】。
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。。?力扣刷題,leetcode,算法,字符串匹配,KMP算法
如果P[next[i-1]] != P[i],那么就要判斷P[next[next[i-1]-1]]和P[i]的關(guān)系,直到下標回溯到0或者找到了和P[i]匹配的位置。
代碼如下(C++):

ector<int> Kmp_Next(string s){
    int n = s.size();
    vector<int>  next(n, 0);
    //next數(shù)組中存的是對應(yīng)下標處子串【包括下標位置】的最長前后綴的長度
    next[0] = 0;
    for(int i = 1; i < n; i++){
        int j = next[i-1];
        while(j>0 && s[j] != s[i]) //不匹配就循環(huán)回退
            j = next[j-1];
        if(s[i] == s[j]) //如果匹配,長度在j的基礎(chǔ)上+1
            j++;
        next[i] = j;
    }
    return next;        
}

KMP的匹配過程:首先求得了模式串P的next數(shù)組,即每個P[0]~P[i]這一段這串中最長的相同前后綴的長度;然后P中的字符從P[j=0]開始,S中的字符也從S[pos=0]開始,判斷S[pos]和P[j]是否匹配,如果匹配就j++,pos++向后移動;如果不匹配,j就根據(jù)next[j-1]回退,并判斷回退后新的下標j對應(yīng)的P[j]和S[pos]是否匹配,如果不匹配繼續(xù)回退,直到匹配或者j=0。實現(xiàn)過程如下:

  • 要先找到P中哪個字符和當前的S[pos]匹配。因為如果P[j] != S[pos],j需要根據(jù)next數(shù)組循環(huán)回退j = next[j-1],那么就先找到能夠匹配的j,才停止;
while(j>0 && haystack[pos] != needle[j])
	j = next[j-1];
  • 上面循環(huán)退出有兩種情況,P[j] == S[pos]或者j == 0;如果是前者,自然pos++,j++;如果是后者,就只有pos++;
if(haystack[pos] == needle[j]){
	pos++;
	j++;
 } 
else
	pos++;  
  • 最后停止要么是j遍歷到了最后,要么是pos遍歷到了最后。只有j遍歷到最后才算完全匹配;

完整代碼如下(C++):


class Solution {
public:
	//先求needle的next數(shù)組
    vector<int> Kmp_Next(string s){
        int n = s.size();
        vector<int>  next(n, 0);
        //next數(shù)組中存的是對應(yīng)下標處子串【包括下標位置】的最長前后綴的長度
        next[0] = 0;
        for(int i = 1; i < n; i++){
            int j = next[i-1];
            while(j>0 && s[j] != s[i])
                j = next[j-1];
            if(s[i] == s[j])
                j++;
            next[i] = j;
        }
        return next;        
    }
    int strStr(string haystack, string needle) {
        vector<int> next = Kmp_Next(needle);
        int pos = 0, j = 0;
        //kmp匹配過程
        while(j < needle.size() && pos < haystack.size()){
            while(j>0 && haystack[pos] != needle[j])
                j = next[j-1];
            if(haystack[pos] == needle[j]){
                pos++;
                j++;
            } 
            else
                pos++;                  
        }
        //needle沒有遍歷完,pos已經(jīng)遍歷完haystack了,沒有匹配的地方
        if(j < needle.size())
            return -1;
        //needle遍歷完,有匹配的地方
        else
            return pos - needle.size();
    }
};

459. 重復(fù)的子字符串

題目鏈接:459. 重復(fù)的子字符串
題目內(nèi)容:
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP?。。?力扣刷題,leetcode,算法,字符串匹配,KMP算法

暴力求解

題目要求我們判斷字符串S是不是由其某個子串重復(fù)構(gòu)成的。假設(shè)子串m能夠重復(fù)構(gòu)成S,那么S可以表示m/mm/m/……這樣的形式,即由n個m組成【n≥2】。分析這樣的子串有兩個特點:

  • 從第一個字符開始;
  • 長度≤S.size()/2;
  • S.size()一定能夠被m.size()整除;

根據(jù)子串的這兩個特點,我們可以去判斷所有這樣的子串,子串長度從1開始,最多有S.size()/2這么多個。針對每個子串,先判斷其長度能否整除S的長度;再判斷其能否重復(fù)構(gòu)成S——將S分成和子串m一樣長度的k個子串,所有的子串和m對比是否一樣,如果有一個不一樣就直接break。
代碼如下(C++):

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int size = s.size();
        //end是子串m的長度
        for(int end = 1; end <= size/2; end++ ){
        	//s長度能夠被end整除才繼續(xù)下面的判斷
            if(size % end == 0){
                int i;
                //剩下的子串和m對比
                for(i = end ; i < size ; i += end ){
                    if(s.substr(0,end) != s.substr(i, end))
                        break;
                }
                if(i == size )
                    return true;
            }      
        }
        return false;
    }
};

暴力求解的時間復(fù)雜度是O(n^2)。

在S+S中找S

假設(shè)S由n個子串m組成【n≥2】,那么S+S中有2n個m,將S+S去頭去尾【刪除第一個和最后一個元素就能實現(xiàn)去掉一個m和最后一個m】后還有2n-2個m,由于n≥2,2n-2≥n。那么如果S+S去頭去尾后還能有至少一個完整的S,就能證明其是由m循環(huán)組成的。代碼實現(xiàn)(C++)【就一句話】:

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        return (s+s).find(s,1) != s.size() ? true : false;
    }
};

那么如果不是由子串m循環(huán)組成的字符串,S+S去頭去尾以后一定找不到一個完整的S嗎?【emm需要再研究一下】

686. 重復(fù)疊加字符串匹配

題目鏈接:686. 重復(fù)疊加字符串匹配
題目內(nèi)容:
【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP!??!,力扣刷題,leetcode,算法,字符串匹配,KMP算法
理解題意,可以發(fā)現(xiàn)題目還是要求我們做字符串匹配。只是查詢串不是簡單的a,而是a的疊加,并且這個疊加次數(shù)是不確定的。
首先我們要明確方法,字符串匹配,首選KMP算法。a的疊加在匹配中可以用a[i % a.size()]來解決。 如果a的m次疊加后,能夠查詢到b,之后的m+1,m+2次疊加b也是其子串, 因此m就是最小的疊加次數(shù)。并且如果能夠找到這樣的m使得b成為a的m次疊加后的子串的話,kmp查詢就能成功,b會被遍歷完。但是如果不能的話,由于a的疊加用a[i % a.size()],a的下標永遠不會越界,b也一直不會遍歷結(jié)束,那么kmp中的循環(huán)該如何結(jié)束?
假設(shè)當前s和b開始匹配的位置是在第一個a之后,因為查詢串s是a重復(fù)循環(huán)疊加的,那么說明在這之前和第一個a也是同樣能夠完成當前的部分匹配的。但是會從第一個a的匹配變到第二個,就說明在當前匹配的字符后有不能匹配的,那么就會繼續(xù)變到第三個a,這樣下去是永遠也不能完全匹配的,即b不是a的循環(huán)疊加的子串。因此得出結(jié)論:s和b開始匹配的地方不是在第一個a中話,可以肯定b不是s的子串,只有b從第一個a中的字符開始匹配才有可能匹配成功。即a中下標i,b中下標 j,如果 **i - j >= a.size()**就說明匹配不上。
代碼如下(C++):文章來源地址http://www.zghlxwxcb.cn/news/detail-700723.html

class Solution {
public:
	//KMP算法
    int strStr(string haystack, string needle) {
        int len_h = haystack.size();
        int len_n = needle.size();
		//求模式串的vector數(shù)組
        vector<int>  next(len_n, 0);
        //next數(shù)組中存的是對應(yīng)下標處子串【包括下標位置】的最長前后綴的長度
        for(int i = 1; i < len_n; i++){
            int j = next[i-1];
            while(j>0 && needle[j] != needle[i])
                j = next[j-1];
            if(needle[i] == needle[j])
                j++;
            next[i] = j;
        }
		//開始匹配
        int pos = 0, j = 0;
        //結(jié)束條件
        while(pos - j < len_h){
            while(j>0 && haystack[pos % len_h] != needle[j])
                j = next[j-1];
            if(haystack[pos % len_h] == needle[j]){
                pos++;
                j++;
            } 
            else
                pos++;
            //因為pos可以無限增加,當遍歷完b的時候說明已經(jīng)找到了    
            if(j == len_n)
                return pos;              
        }
        return -1;
    }
    int repeatedStringMatch(string a, string b) {
        int idx = strStr(a, b);
        if(idx == -1)
            return -1;
        //求m
        return  (idx-1) / a.size() + 1;

    }
};

到了這里,關(guān)于【leetcode 力扣刷題】字符串匹配之經(jīng)典的KMP!??!的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • LeetCode刷題——394. 字符串解碼(HOT100)

    ?????大家好!本篇文章將較詳細介紹棧的題目 394. 字符串解碼 ,提供 棧和遞歸 兩種解法。代碼語言為: C++代碼 ??。 ??1、題目: 給定一個經(jīng)過編碼的字符串,返回它解碼后的字符串。 編碼規(guī)則為: k[encoded_string] ,表示其中方括號內(nèi)部的 encoded_string 正好重復(fù) k 次。注

    2024年01月19日
    瀏覽(37)
  • 【刷題】 leetcode 面試題 01.06 字符串壓縮

    【刷題】 leetcode 面試題 01.06 字符串壓縮

    來看題目: 根據(jù)題目所說,我們需要完成函數(shù)書寫,保證返回一個相對較小的字符數(shù)組: 如果壓縮后比原字符串小,則返回壓縮字符串,否則返回原字符串。 本思路一步一步操作,逐步完成任務(wù) 先確認字符串長度是否小于 2 ,小于直接返回( 因為壓縮字符串長度至少是2

    2024年01月24日
    瀏覽(89)
  • Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一個匹配項的下標

    摘要: Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一個匹配項的下標 。題目介紹:給你兩個字符串 haystack 和 needle ,請你在 haystack 字符串中找出 needle 字符串的第一個匹配項的下標(下標從 0 開始)。如果 needle 不是 haystack 的一部分,則返回 -1 。 題目介紹 :給你兩

    2024年02月02日
    瀏覽(28)
  • LeetCode28. 找出字符串中第一個匹配項的下標

    給你兩個字符串?haystack 和 needle ,請你在 haystack 字符串中找出 needle 字符串的第一個匹配項的下標(下標從 0 開始)。如果?needle 不是 haystack 的一部分,則返回??-1 。 示例 1: 輸入:haystack = \\\"sadbutsad\\\", needle = \\\"sad\\\" 輸出:0 解釋:\\\"sad\\\" 在下標 0 和 6 處匹配。 第一個匹配項的下

    2024年02月08日
    瀏覽(22)
  • 【LeetCode】28 . 找出字符串中第一個匹配項的下標

    【LeetCode】28 . 找出字符串中第一個匹配項的下標

    思路 使用 find 函數(shù)枚舉原串 ss 中的每個字符作為「發(fā)起點」,每次從原串的「發(fā)起點」和匹配串的「首位」開始嘗試匹配: 匹配成功:返回本次匹配的原串「發(fā)起點」。 匹配失?。好杜e原串的下一個「發(fā)起點」,重新嘗試匹配。 代碼

    2024年02月10日
    瀏覽(25)
  • LeetCode 28題:找出字符串中第一個匹配項的下標

    LeetCode 28題:找出字符串中第一個匹配項的下標

    給你兩個字符串? haystack ?和? needle ?,請你在? haystack ?字符串中找出? needle ?字符串的第一個匹配項的下標(下標從 0 開始)。如果? needle ?不是? haystack ?的一部分,則返回?? -1 ? 。 示例 1: 示例 2: 提示: 1 = haystack.length, needle.length = 104 haystack ?和? needle ?僅由小寫

    2024年02月14日
    瀏覽(35)
  • 【Py/Java/C++三種語言詳解】LeetCode每日一題240117【哈希集合】LeetCode2744、最大字符串匹配數(shù)目

    LeetCode2744、最大字符串匹配數(shù)目 給你一個下標從 0 開始的數(shù)組 words ,數(shù)組中包含 互不相同 的字符串。 如果字符串 words[i] 與字符串 words[j] 滿足以下條件,我們稱它們可以匹配: 字符串 words[i] 等于 words[j] 的反轉(zhuǎn)字符串。 0 = i j words.length 請你返回數(shù)組 words 中的 最大 匹配數(shù)

    2024年01月18日
    瀏覽(18)
  • 【leetcode 力扣刷題】匯總區(qū)間//合并區(qū)間//插入?yún)^(qū)間

    【leetcode 力扣刷題】匯總區(qū)間//合并區(qū)間//插入?yún)^(qū)間

    題目鏈接:228.匯總區(qū)間 題目內(nèi)容: 看題目真是沒懂這個題到底是要干啥……實際上題目要求的 恰好覆蓋數(shù)組中所有數(shù)字 的 最小有序 區(qū)間范圍列表,這個最小是指一個區(qū)間范圍小。比如能夠覆蓋{2,3,4,6}的區(qū)間可以是[2,6],但是5在區(qū)間內(nèi),卻不在數(shù)組內(nèi),因此這個區(qū)間不是最

    2024年02月10日
    瀏覽(33)
  • leetcode 力扣刷題 旋轉(zhuǎn)矩陣(循環(huán)過程邊界控制)

    leetcode 力扣刷題 旋轉(zhuǎn)矩陣(循環(huán)過程邊界控制)

    下面的題目的主要考察點都是,二維數(shù)組從左上角開始順時針(或者逆時針)按圈遍歷數(shù)組的過程。順時針按圈遍歷的過程如下: 對于每一圈,分為四條邊 ,循環(huán)遍歷就好。這時,對于 四個角 的元素的處理,可以將四條邊的遍歷分為以下兩種情況: 第一種:每條邊都從對

    2024年02月12日
    瀏覽(21)
  • 【leetcode 力扣刷題】鏈表基礎(chǔ)知識 基礎(chǔ)操作

    【leetcode 力扣刷題】鏈表基礎(chǔ)知識 基礎(chǔ)操作

    在數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)過程中,我們知道線性表【一種數(shù)據(jù)組織、在內(nèi)存中存儲的形式】是線性結(jié)構(gòu)的,其中線性表包括順序表和鏈表。數(shù)組就是順序表,其各個元素在內(nèi)存中是連續(xù)存儲的。 鏈表則是由 數(shù)據(jù)域 和 指針域 組成的 結(jié)構(gòu)體 構(gòu)成的,數(shù)據(jù)域是一個節(jié)點的數(shù)據(jù),指針域

    2024年02月12日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包