SAM學習筆記


-1.參考資料

oi wiki

嗯,改了一些可能是錯誤的地方(迫真

0.定義

定義 \(\Sigma\) 表示字符集。

定義 \(a\sqsubseteq b\) 表示 \(a\)\(b\) 的后綴。

定義 \(a\sqsubset b\) 表示 \(a\)\(b\) 的真后綴。

定義 \(|s|\) 表示 \(s\) 的長度。

定義 \(u-v\) 表示 \(u\)\(v\) 的路徑上節點組成的集合。

1.關於SAM

  • Q:SAM 是什么?可以吃嗎?
  • A:SAM 全稱后綴自動機(\(\texttt{Suffix Automation}\)),是一個接受 \(s\) 的所有后綴的最小 DFA ,不可以吃。
  • Q:DFA 是什么?可以吃嗎?
  • A:DFA 全稱確定有限狀態自動機(\(\texttt{Deterministic Finite Automaton}\)),也不可以吃。DFA 由五個部分組成:
  1. 字符集(\(\Sigma\)),自動機中的所有字符均在字符集中。
  2. 狀態集合(\(Q\)),如果將 DFA 看成 DAG ,那么 \(Q=V\)
  3. 起始狀態(\(s\)),\(s\in Q\),是一個特殊的狀態。
  4. 接受狀態(\(F\)),\(F\subseteq Q\),是一堆特殊的狀態。
  5. 轉移函數(\(\delta\)),如果將 DFA 看成 DAG ,那么 \(\delta=w\) ,且 \(\delta:V\times V\rightarrow \Sigma\),此處乘法表示笛卡爾積。

總結一下:

  • SAM 是一個特殊的 DAG,結點稱為狀態,邊稱為轉移。
  • 存在源點(初始狀態) \(t_0\),其他結點均由 \(t_0\) 可達。
  • 存在多個匯點(終止狀態),滿足任意一條由源點到匯點的路徑上轉移函數拼接組成的字符串均為原字符串的后綴。(這也是其被稱為后綴自動機的原因)
  • 在所有滿足以上條件的自動機中,SAM 是結點個數最少的。具體地,\(|V|=2n-1,|E|=3n-4\)

由定義我們可以得到一個簡單的推論:由源點引出的所有路徑上轉移函數拼接組成的字符串(包括連到自己的路徑,這種情況下我們視為空串)構成的集合即為該字符串的所有子串構成的集合,證明顯然。

2.SAM 舉例

盜來了幾張 oi-wiki 上的圖:

  1. 空串:
  2. \(s=\texttt{a}\)
  3. \(s=\texttt{aa}\)
  4. \(s=\texttt{ab}\)
  5. \(s=\texttt{abb}\)
  6. \(s=\texttt{abbb}\)

3.線性構造 SAM

Note:下面出現的一切字符串都是 \(s\) 的非空子串。

3.1 endpos

定義 \(\operatorname{endpos}(t)\) 表示在字符串 \(s\)\(t\) 的所有結束位置。

例如,當 \(s=\texttt{abcbc}\) 的時候,\(\operatorname{endpos}(\texttt{bc})=\{2,4\}\)

我們稱 \(s,t\) 為等價類,當且僅當 \(\operatorname{endpos}(s)=\operatorname{endpos}(t)\),於是我們可以將 \(s\) 的所有非空子串分為若干等價類。

則顯然 SAM 上除了初始狀態的每一個狀態都對應一個等價類。

因為每個狀態都能對應多個 \(\operatorname{endpos}\) 相同的子串,也就是等價類,所以等價類的個數加上 1,就是SAM狀態的個數!

下面我們會給出一些關於 \(\text{endpos}\) 的性質。

Lemma 1\(|u|\le |w|\),那么 \(u\)\(w\) 是等價類的充要條件是每次 \(u\) 出現都是作為 \(w\) 的后綴。

證明顯然。

Lemma 2\(|u|\le |w|\),有:

\[\begin{cases}\operatorname{endpos}(w)\subseteq \operatorname{endpos}(u)&u\sqsubseteq w\\\operatorname{endpos}(u)\cap \operatorname{endpos}(w)=\varnothing&otherwise\end{cases} \]

Proof

\(\operatorname{endpos}(u)\cap \operatorname{endpos}(w)\neq\varnothing\),則 \(u\)\(w\) 在相同位置結束,則 \(u\sqsubseteq w\),所以 \(\operatorname{endpos}(w)\subseteq \operatorname{endpos}(u)\),反之亦然,得證。

Lemma 3
(1)對於同一個等價類中的兩個子串 \(s,t\),且 \(|s|\le |t|\),有 \(s\sqsubseteq t\)
(2)一個等價類中的所有子串的長度,可以恰好不重復地覆蓋一段連續區間。

Proof

如果等價類中只有一個子串,那么結論顯然成立。

考慮有至少兩個子串的情況,由 Lemma 1,短的子串是長的子串的后綴,所以等價類中子串長度兩兩不同。

設最長串為 \(u\),最短串為 \(w\),由 Lemma 1,\(w\sqsubset u\)

考慮長度在 \([|u|,|w|]\) 之間的 \(w\) 的后綴,由 Lemma 1,這些字符串都在等價類中,所以(2)得證。

又因為等價類中子串長度兩兩不同,所以等價類中只有這些字符串,所以(1)得證。

取一個狀態 \(v\neq t_0\),我們目前已經得到了如下結論:

  1. \(v\) 對應一個等價類
  2. 如果設 \(w\) 是這個等價類中最長的一個,那么其他的字符串都是 \(w\) 的后綴。
  3. 如果將 \(w\) 的后綴按照長度降序排序,那么 \(w\) 的前幾個后綴都在這個等價類中,且剩下的都不在。

我們設 \(t\) 是所有 \(w\) 的后綴中,最長的與 \(w\) 不在一個等價類中的后綴,那么定義 \(\text{link}(v)=t\),即把 \(v\) 的后綴鏈接連到 \(t\) 上。

也就是說,一個后綴鏈接連接到對應於 \(w\) 的最長后綴的另一個等價類的狀態。

下面給出一些性質。

P.S.為了方便起見,定義 \(\operatorname{endpos}(t_0)=\{-1,0,\cdots,|S|-1\}\)

Lemma 4:所有后綴鏈接構成一棵根節點為 \(t_0\) 的樹,一般稱之為 Parent Tree

Proof

證:\(\forall v\neq t_0\),由 Lemma 3,后綴鏈接連接的狀態對應的字符串長度嚴格小於該狀態字符串長度,因此必然會通向 \(t_0\),又因為恰有 \(|V|-1\) 條邊,所以構成樹。

Lemma 5\(\operatorname{endpos}(s)\subseteq \operatorname{endpos}(\operatorname{link}(s))\)。亦即,parent tree的子節點的 endpos 是父節點的 endpos 的子集。

Proof

證:由定義 \(\operatorname{link}(s)\sqsubseteq s\) 由 Lemma 2 得證。

這是一張 parent tree 對應自動機的圖:

3.3 一些定義&小結

在學習算法之前,先來一些定義。

  • 定義 \(\operatorname{longest}(v)\) 為狀態 \(v\) 對應等價類中最長的字符串,\(\operatorname{len}(v)=|\operatorname{longest}(v)|\)
  • 定義 \(\operatorname{shortest}(v)\) 為狀態 \(v\) 對應等價類中最短的字符串,\(\operatorname{minlen}(v)=|\operatorname{shortest}(v)|\)

所以由 Lemma 3 以及 link 的定義立得:

\[\operatorname{minlen}(v)=\operatorname{len}(\operatorname{link}(v))+1 \]

下面是以上定理的總結:

  • \(s\) 的子串可以根據 endpos 划分為若干等價類。
  • SAM 由初始狀態和等價類對應的狀態構成。
  • 對於狀態 \(v\neq t_0\),有以下結論:
  1. 此狀態對應的字符串均為 \(\operatorname{longest}(v)\) 后綴,且長度恰好覆蓋 \([\operatorname{minlen}(v),\operatorname{len}(v)]\)
  2. \(\operatorname{endpos}(v)\subseteq \operatorname{endpos}(\operatorname{link}(v))\)
  3. parent tree 上 \(t_0-v\) 存在,且路徑上每個節點對應的區間互不相交,並集恰為 \([0,\operatorname{link}(v)]\)

3.4 算法

這個算法是在線算法,也就是說可以每次加一個字符,同時更新SAM。

下面我們以字符串 \(\texttt{abcbc}\) 對應 SAM 為例,考慮加上一個 \(\texttt b\)(下面標記為字符 \(c\))。

下面的圖分別表示 SAM 和 parent tree。

注:節點上的字符串表示 \(\operatorname{longest}(v)\),邊上的字符串表示轉移函數的值,藍色點是初始狀態,綠色點是終止狀態。實際算法時,我們只會對每個點記錄轉移到的點,\(\operatorname{len}\)\(\operatorname{link}\)

在算法流程中,我們取 \(last\) 表示整個字符串對應的狀態,每次更新完自動機后再更新 \(last\),比如在上面的圖中,\(last\) 就是 ABCBC 對應的點,后面會標記為橙色。

  1. 新建狀態 \(cur\),並令 \(\operatorname{len}(cur)=\operatorname{len}(last)+1\)\(\operatorname{longest}(v)=s\),后面會用紅色標記。
  2. \(last\) 開始在 parent tree 上暴力跳祖先,只要跳到有到 \(c\) 的轉移就停下,並將跳過的路徑上的所有點
    (包括 \(last\),不包括該點)全部向 \(cur\) 連轉移為 \(c\) 的邊,將此點設為 \(p\)。比如在這個例子中,找到的 \(p\) 就是 \(\texttt{BC}\) 對應的狀態,用黃色標記,下面是操作好的自動機。
  3. 如果發現 \(p\) 不存在,那么令 \(\operatorname{link}(cur)=t_0\),結束;否則,我們設它通過 \(c\) 轉移到的狀態為 \(q\),標記為青色。比如在上圖中,\(\texttt{ABCB}\) 對應的狀態就是 \(q\)
  4. 如果發現 \(\operatorname{len}(p)+1=\operatorname{len}(q)\),那么令 \(\operatorname{link}(cur)=q\),結束。
  5. 否則我們新建一個狀態 \(clone\),復制 \(q\)\(\operatorname{link}\) 以及轉移的信息,並且令 \(\operatorname{len}(clone)=\operatorname{len}(p)+1\) ,將 \(clone\) 標記為紫色,下面是操作好的自動機和 parent tree。
  6. 然后我們令 \(\operatorname{link}(cur)=\operatorname{link}(q)=clone\),下面是操作好的 parent tree。
  7. 最后我們用 parent tree 從 \(p\) 往上跳,跳到的點只要對 \(q\) 有轉移,就重定向到 \(clone\),下面是操作好的自動機。

注:易證這些有轉移的點是連續的,實現時只要發現不能轉移就終止。
8. 完成以上操作之后,我們將 \(last\) 的值更新為 \(cur\),並轉化為初始自動機的形式,如圖所示。

這里補充一下怎么找到終止狀態的:parent tree 上從 \(last\) 節點往上跳,跳的時候經過的所有狀態都是終止狀態,因為這樣可以遍歷所有 \(s\) 的后綴。

下面是代碼實現:

Code
struct node{int len,link,to[30];};
struct Suffix_Automation{
	node state[N];
	int rt=1,last=1,tot=1;
	void extend(int ch){
		int cur=++tot,p,q;
		state[cur].len=state[last].len+1;
		for(p=last;p&&!state[p].to[ch];p=state[p].link)state[p].to[ch]=cur;
		if(!p)state[cur].link=rt;
		else{
			q=state[p].to[ch];
			if(state[p].len+1==state[q].len)state[cur].link=q;
			else{
				int clone=++tot;
				state[clone]=state[q];
				state[clone].len=state[p].len+1;
				state[cur].link=state[q].link=clone;
				for(;p&&state[p].to[ch]==q;p=state[p].link)state[p].to[ch]=clone;
			}
		}
		last=cur;
	}
}SAM;

4.應用

咕咕咕~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM