1. 程式人生 > >【文文殿下】後綴自動機(SAM)求最長公共子串的方法

【文文殿下】後綴自動機(SAM)求最長公共子串的方法

size 有一點 span 成功 移動 同步 轉移 模板 繼續

首先,在A 串上建立一個SAM,然後用B串在上面跑。具體跑的方法是:

從根節點開始,建立一個指針 p ,指著B串的開頭,同步移動指針,沿著SAM的邊移動,如果可以移動(即存在邊)那麽萬事皆好,直接len++就好,但是,如果無法繼續轉移(失配了),那麽,我們考慮跳回其父節點,因為其父節點的Right集是當前狀態的真超集,那麽其父節點狀態所代表的字符串的集合中的任意一個字符串,都是當前狀態所代表的字符串集合中的正在匹配的字符串(會不會一定是最長串?)的後綴,所以,有一個貪心的思想:父節點狀態中的最長串一定是合法的,我們順著父節點找上去,一定最終可以找到一個節點允許下一個字符轉移,或者找到了0號節點。

第一種情況:找到了一個合適的狀態,那麽大家都好,直接從這裏繼續跑,同時把len強制更新為Max(G)(這裏要不要+1有一點爭論,如果+1,那麽接下來跑串時,之前失配的那個字符可能對答案貢獻了2次?,因為跑到下一個狀態時,是沿著之前那個失配字符的那條邊跑的,這會導致len++,所以我認為這裏不應該+1),因為我們之前跑的那個已經成功的串,這裏一定取那個已經匹配了的最長後綴,然後接下來繼續跑串。

第二中情況:我們無法找到一個狀態擁有x這條邊,就算是根節點也沒有這個邊,說明模板串出現了一個原串中沒有出現的字符,我們強制更新當前狀態為根節點,然後把指針p從字符x挪過去,從他的下一個字符開始匹配。

但實際上,我們沒必要考慮第二種情況:我們先預處理模板串,把原串中不存在的字符去掉,把模板串分成一個個小的模板串,然後從最大的模板串跑匹配,記錄當前答案,這裏有一個顯而易見的優化:如果即將跑的模板串長度低於全局答案,那麽我們跳過這個模板串。

事實上,len不應該設為Max(G)+1

【文文殿下】後綴自動機(SAM)求最長公共子串的方法