數據結構:KMP算法

1.何為KMP算法

? ? ?KMP算法是由Knuth、Morris和Pratt三位學者發明的,所以取了三位學者名字的首字母,叫作KMP算法。

2.KMP的用處

? ? ?KMP主要用于字符串匹配的問題,主要思想是當出現字符串不匹配時,我們可以知道一部分之前已經匹配過的的文本內容,利用這些信息從而避免從頭再開始匹配。

? ? ?但是如何才能知道之前已經匹配過的內容呢?這是KMP算法的核心,也是KMP算法里面的next數組的用處。

3.最長相等前后綴

? ? ?一個字符串的前綴是指不包含最后一個字符的所有以第一個字符開頭的連續字串

? ? ?后綴是指不包含第一個字符的所有以最后一個字符結尾的連續子串

? ? ?前綴表也就是next數組要求的是最長相等前后綴的長度,例如a的最長相等前后綴為0,aaa得到最長相等前后綴為2,aaba的最長相等前后綴為1。

4.next數組(前綴表)

? ? ?KMP的核心就是next數組,當模板串和主串不匹配時,next數組是用來讓模板串知道應該從哪里再開始匹配。

? ? ?next數組記錄下標i之前(包括i)的字符串中,有多大長度的相等前后綴。

? ? ?這里借用了代碼隨想錄的圖片

? ? ?比如我們要在文本串aabaabaafa中尋找模板串aabaaf,在b和f之前發現匹配不了,如果用暴力算法,就要從頭開始匹配,文本串和模板串都需要進行回退,時間復雜度是很高的,但如果我們使用KMP算法,next數組記錄了f之前有多大長度的相等前后綴,也就是我們知道了之前匹配過的內容,就會從上次已經匹配的內容開始匹配,這里為什么能這樣呢?我是這樣理解的:

? ? ?文本串: aabaabaafa ?用i遍歷

? ? ?模板串:aabaaf ? ? ?用j遍歷

? ? ?在b和f時不相同了,這時候我們不想再匹配我們已經匹配過的,也就是說我們不想i回退,而是一直向前走,那我們就要j進行回退,回退到什么位置呢,前面已經匹配到了,說明已經匹配過的文本串aabaa中含有模板串一部分內容,又因為前后綴有相等的部分。所以我們回退到前后綴相等的前綴位置,因為和文本串是相同的,所以aabaa的后綴aa和文本串的aabaa的后綴aa是相等的,又有aabaa的前綴aa和后綴aa是相等前后綴,所以前綴aa和文本串aabaa的后綴aa相等,我們回退到aabaa的b即可避免再次匹配aabaa的前綴aa,這樣也可以保證模板串aabaa的前綴aa是已經匹配過的。

? ? ? f之前這部分的字符串(也就是字符串aabaa)的最長相等前后綴是aa ,因為找到了最長相等的前后綴,匹配失敗的位置是后綴的后面,那么我們找到與其相同的前綴的后面重新匹配就可以了。

5.如何計算next數組

?例如a a b a a f下標0 1 2 3 4 5next 0 1 0 1 2 0

? ? ?當下標為0時,長度為前1個字符的字串a,最長相等前后綴的長度為0

? ? ?當下標為1時,長度為前2個字符的字串aa,最長相等前后綴的長度為1

? ? ?依次類比,可以得到next數組,也就是前綴表

? ? ?可以看出模板串和next數組對應位置的數字表示的是下標i之前(包括i)的字符串中,有多大長度的最長相等前后綴。

? ? ? 當我們找到不匹配的位置時,就要看它前一個字符的next數組的值是多少,因為我們要找前面字符串的最長相等前后綴,所以要看前一位的next數組的值,前一個字符的next數組值為2,所以我們把下標j移動到2的位置繼續匹配,這樣就可以匹配到了。

6.next數組實現

? ? ?主要是處理前后綴相等和不相等的情況,我們首先定義一個getNext函數來構造next數組,參數為指向next數組的指針,和一個字符串

void getNext(int* next,string& s)

? ? ?接著我們對其進行初始化,定義兩個指針i和j,j指向前綴末尾,i指向后綴末尾,對next數組進行初始化賦值

int j=0;
next[0]=j;

? ? ?next[i]表示i(包括i)之前最長相等的前后綴長度,就是j,所以初始化next[0]=j

6.1前后綴不相同

? ? ?j=0,所以我們從i=1開始,遍歷文本串,就像這樣

for(int i=0;i<s.size();i++)

? ? ? j首先要保證是大于0的,因為下面j要回退,然后就是s[i]和s[j]的比較,如果s[i]和s[j]不相同,j就要找前一位對應的回退位置,因為這里j之前的前綴已經和i的后綴不相等了,所以我們就要j進行回退。

while(j>=0&&s[i]!=s[j])
{j=next[j-1];
}

?6.2前后綴相同

? ? ?如果是s[i]和s[j]相同,這時候只要同時移動i和j,這時候找到了相同的前后綴,我們要把j的值賦值給next[i],因為next[i]記錄相同前后綴的長度

if(s[i]==s[j])
{j++;
}
next[i]=j;

? ? ? 完整代碼如下:?

void getNext(int* next, const string& s) 
{int j = 0;next[0] = 0;for(int i = 1; i < s.size(); i++) {while (j > 0 && s[i] != s[j]){ j = next[j - 1]; }if (s[i] == s[j]){j++;}next[i] = j;}
}

7.例題? ??

?

  void getNext(int* next,const string& s){int j=0;next[0]=0;for(int i=1;i<s.size();i++){while(j>0&&s[i]!=s[j]){j=next[j-1];}if(s[i]==s[j]){j++;}next[i]=j;}}int strStr(string haystack,string needle){if(needle.size()==0){return 0;}int next[needle.size()];getNext(next,needle);int j=0;for(int i=0;i<haystack.size();i++){while(j>0&&haystack[i]!=needle[j]){j=next[j-1];}if(haystack[i]==needle[j]){j++;}if(j==needle.size()){return (i-needle.size()+1) ;}}return -1;}

? ? ?這道題很明顯是字符串匹配的問題,所以我們使用KMP算法,首先是next數組的構建,這是模板,直接寫就行,然后就是模板串和文本串的匹配,如果不相同,那j就回退到next[j-1],如果相同,j就直接向后移動即可,當j和模板串的長度相等時,此時i一定是大于等于模板串的長度的,因為i之前的文本串是包含模板串的,所以我們用i-模板串的長度+1就是第一個匹配項的下標了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/536667.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536667.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536667.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【期刊周報1】醫學好刊(SCI/SSCI/EI),含Top,領域廣,接收快!

為了向廣大學者朋友提供更優質的選刊服務&#xff0c;提高選刊質量&#xff0c;我處現開設周報專欄&#xff0c;以羅列我處合作的優質期刊~ 本期&#xff0c;小編給大家推薦的是醫學領域相關的熱門期刊&#xff0c;接收領域廣&#xff0c;無預警&#xff0c;且在最新檢索目錄內…

Python遙感影像深度學習指南(2)-在 PyTorch 中創建自定義數據集和加載器

在上一篇 文章中,我們Fast.ai 在衛星圖像中檢測云輪廓,檢測物體輪廓被稱為語義分割。雖然我們用幾行代碼就能達到 96% 的準確率,但該模型無法考慮數據集中提供的所有輸入通道(紅、綠、藍和近紅外)。問題在于,深度學習框架(如 Keras、Fast.ai 甚至 PyTorch)中的大多數語…

油煙凈化器如何做到高效凈化?科技力量,清新餐飲生活

我最近分析了餐飲市場的油煙凈化器等產品報告&#xff0c;解決了餐飲業廚房油膩的難題&#xff0c;更加方便了在餐飲業和商業場所有需求的小伙伴們。 油煙凈化器的出現&#xff0c;為我們的餐飲生活注入了一抹清新的色彩。然而&#xff0c;它究竟是如何工作的&#xff1f;為何能…

【開題報告】基于SSM的健康飲食系統設計與實現

1.研究背景 如今&#xff0c;隨著人們生活水平的提高和健康意識的增強&#xff0c;越來越多的人開始關注自己的飲食習慣&#xff0c;并希望通過合理的飲食來維持身體健康。然而&#xff0c;對于許多人來說&#xff0c;了解和選擇合適的飲食方式并不容易。傳統的飲食指導往往比…

【并發設計模式】聊聊Immutability模式利用不變性解決并發問題

上一篇文章&#xff0c;我們介紹了如何利用二階段停止協議進行優雅停止線程和線程池&#xff0c;本篇介紹在并發編程中數據安全性&#xff0c;我們知道針對于數據的操作&#xff0c;讀和寫(添加、刪除、修改), 在并發線程讀寫的時候&#xff0c;變量不加鎖的情況下&#xff0c;…

redis哨兵+redis主從復制(在虛擬機centos的docker下)

1.安裝docker Docker安裝(CentOS)簡單使用-CSDN博客 2.redis主從復制 redis主從復制(在虛擬機centos的docker下)-CSDN博客 3.編輯3個redis配置 cd /etc mkdir redis-sentinel cd redis-sentinel/ wget http://download.redis.io/redis-stable/sentinel.confcp sentinel.co…

ssh 免密登陸公鑰設置失敗分析調試

前景 看到這里肯定已經知道如何設置免密登陸。本文主要用于解決免密登陸設置失效問題。 ssh調試 目的 ssh設置了公鑰仍然無法免密登陸; 需要調試 解決 通過systemctl status sshd的日志輸出查看原因 步驟 打開調試 systemctl status sshd查看所在服務文件 $ sudo sys…

【并發編程篇】讀鎖readLock()和寫鎖writeLock()

文章目錄 &#x1f6f8;情景引入?解決問題 readLock()和writeLock()都是ReadWriteLock接口中定義的方法&#xff0c;用于獲取讀鎖和寫鎖。 readLock()方法返回一個讀鎖&#xff0c;允許多個線程同時獲取該鎖&#xff0c;以進行并發讀取操作。如果當前已有一個寫鎖或其他線程正…

GIT具體配置步驟詳解

GIT配置具體步驟如下 SDK 使用 Repo 工具管理&#xff0c;拉取 SDK 需要配置安裝 Repo 工具。 Repo is a tool built on top of Git. Repo helps manage many Git repositories, does the uploads to revision control systems, and automates parts of the development workf…

裝飾器模式和責任鏈模式區別

近期看了 mybatis 的源碼&#xff0c;發現二級緩存這塊用了裝飾器模式將各個功能的緩存進行嵌套&#xff0c;源碼上也是講到使用了裝飾器模式&#xff0c;但是看著跟責任鏈模式類似&#xff0c;本著搞清楚的想法&#xff0c;搜了很多資料&#xff0c;看了書籍《Head First 設計…

AI行業新趨勢:百模大戰中的變革與未來

AI行業新趨勢&#xff1a;百模大戰中的變革與未來 人工智能&#xff0c;這個曾經被視為科幻小說的情節&#xff0c;如今已經成為我們生活中的常態。從智能手機、自動駕駛汽車&#xff0c;到智能家居、醫療診斷&#xff0c;AI的應用已經深入到我們生活的各個角落。然而&#xf…

多維時序 | MATLAB實CNN-BiGRU-Mutilhead-Attention卷積網絡結合雙向門控循環單元網絡融合多頭注意力機制多變量時間序列預測

多維時序 | MATLAB實現CNN-BiGRU-Mutilhead-Attention卷積網絡結合雙向門控循環單元網絡融合多頭注意力機制多變量時間序列預測 目錄 多維時序 | MATLAB實現CNN-BiGRU-Mutilhead-Attention卷積網絡結合雙向門控循環單元網絡融合多頭注意力機制多變量時間序列預測預測效果基本介…

ubuntu 22.04 安裝mysql服務

完整內容&#xff1a; https://developer.aliyun.com/article/1260321 # 安裝服務 sudo apt install mysql-server# 按向導設置root密碼 sudo mysql_secure_installation# 使用設置的密碼登錄 sudo mysql -u root -p也可以使用工具登錄&#xff0c;例如: navicat for mysql

協同工作php,PHPOA:靈活、高效、協同,讓企業高效運轉

原標題&#xff1a;PHPOA&#xff1a;靈活、高效、協同&#xff0c;讓企業高效運轉PHPOA系統作為一個管理系統&#xff0c;它的職責就是為企業高效運轉而服務&#xff0c;以提高企業的辦公效率為己任&#xff0c;減少不必要的資源浪費為責任。它保持高度的靈活性、高效性與協同…

ubuntu搭建php開發環境記錄

2019獨角獸企業重金招聘Python工程師標準>>> 這兩天自己在阿里云上面買了一個ecs&#xff0c;系統選的是ubuntu16.04&#xff0c;第一件事就是先搭環境&#xff0c;這次準備使用lamp組合。 Apache安裝 首先安裝apache服務器&#xff0c;ubuntu下面使用apt-get來下載…

php datediff 函數,dateAdd與DateDiff函數的js代碼

1、DateAdd函數&#xff1a;復制代碼 代碼示例:function DateAdd(interval,number,date){switch(interval.toLowerCase()){case "y": return new Date(date.setFullYear(date.getFullYear()number));case "m": return new Date(date.setMonth(date.getMont…

mysql索引為啥要選擇B+樹 (下)

有讀者在 mysql索引為啥要選擇B樹 (上) 上篇文章中留言總結了選擇 B 樹的原因&#xff0c;大體上說對了&#xff0c;今天我們再一起來看看具體的原因。 索引為什么要保存在硬盤中首先要明白幾個概念&#xff0c;服務器存儲一般分內存和硬盤&#xff0c;內存的大小相對于硬盤來說…

des加解密java c#,C#編寫DES加密、解密類

這個C#類封裝的DES加密解密&#xff0c;可以使用默認秘鑰進行加密、解密&#xff0c;也可以自定義秘鑰進行加密、解密&#xff0c;調用簡單方便。示例一&#xff1a;using System;using System.Security.Cryptography;using System.Text;namespace DotNet.Utilities{/// /// DE…

八年開發程序員淺析SpringBoot 之 Shiro 與 Redis 多級緩存問題

前言 來自不愿意透露姓名的小師弟的投稿。這篇主要講了&#xff0c;項目中配置了多緩存遇到的坑&#xff0c;以及解決辦法。 發現問題 在一次項目實踐中有實現多級緩存其中有已經包括了 Shiro 的 Cache &#xff0c;本以為開啟 redis 的緩存是一件很簡單的事情只需要在啟動類上…

Web端H.265播放器研發解密

音視頻編解碼對于前端工程師是一個比較少涉足的領域&#xff0c;涉及到流媒體技術中的文本、圖形、圖像、音頻和視頻多種理論知識的學習&#xff0c;才能夠應用到具體實踐中&#xff0c;本團隊在多媒體領域深耕兩年多&#xff0c;才算是有一定產出&#xff0c;我們自研web播放器…