ãã®è¨äºã¯Advent Calendar 2014ã®12/1ã®è¨äºã¨ãã¦æ¸ããã¾ããã
ã¯ããã«
KMPãManacherãZ algorithm ã®ï¼ã¤ã«ã¤ãã¦æ¸ãããã¨æãã¾ãã
ï¼ã¢ã«ã´ãªãºã ï¼ï¼æ¥ã§è¿½è¨ãã¦è¡ãã¾ãã
ãããã®ã¢ã«ã´ãªãºã ã§ã¯ãæ±ããããã®ã®ç¹æ§ãçããã¦ãæ¢ã«è¨ç®ããçµæãä¸æã«å©ç¨ãããã¨ããç¹ã§å
±éãã¦ãããããããããªãã»ã©ãªããã¨è¨ãããã¾ããã
ãã®ç¾ããã¢ã«ã´ãªãºã ãã¡ãæ¯éç´¹ä»ãããã¨æãããã®è¨äºãæ¸ããã¨ã«ãã¾ããã
ã»è¨æ³ã«ã¤ãã¦
|S|ï¼æåå S ã®é·ãã表ãã
S[i,j]ï¼æåå S ã® i æåç®ãã j æåç®ã¾ã§ãåãåºããæååã表ãã
KMP
â»ããã¯æ£ç¢ºã«ã¯KMPã§ã¯ãªãMPã§ããKMPã«ã¤ãã¦ã¯こちらã
æåå S ãä¸ããããã¨ãã«ãå i ã«ã¤ãã¦ãæååS[0,i-1]ã®æ¥é è¾ã¨æ¥å°¾è¾ãæ大ä½æåä¸è´ãã¦ãããããè¨é²ããé
åã O(|S|)ã§æ§ç¯ããã¢ã«ã´ãªãºã ã§ãããã ãã|S[0,i-1]|æªæºã®ãã®ã®ã¿ãèæ
®ãã¾ãã
ä¾ãã°ã
aabaabaaa _010123452
ãããªæãã§ãã(i=0ã®å ´æã¯é©åãªå¤ãåå¨ããªãã®ã§_(-1ã®æå³ã§ä½¿ã£ã¦ãã¾ã)ã¨ããå
¥ãã¾ãã)
(çå¹
ãã©ã³ãããç¡ãå ´åã¯çå¹
ãã©ã³ãã§è¦ã¦ã)
この配列を使うと文字列検索や周期性の判定などが高速に行えるようになるのですが、その辺りの説明は他のサイトにお任せします。
çµè«ããè¨ãã¨ãMPã®ã³ã¼ãã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
A[0] = -1; int j = -1; for (int i = 0; i < S.size(); i++) { while (j >= 0 && S[i] != S[j]) j = A[j]; j++; A[i+1] = j; }
ãã®ã³ã¼ããä½ããã¦ããã®ããè¦ã¦ããã¾ãã
j ã®åãã«æ³¨ç®ãã¾ããåforæã®ã¹ããããå®è¡ããå¾ã®jã®å ´æã追ã£ã¦ã¿ã¾ãã
S : abbabba 1 : ji_____ 2 : j_i____ 3 : _j_i___ 4 : __j_i__ 5 : ___j_i_ 6 : ____j_i
j 㯠A[i+1] ã示ãã¦ãã¾ããS[0:j-1]ã¨S[i-j+1:i]ã¯ä¸è´ãã¦ãã¾ããã
S[i]ã¨S[j]ãä¸è´ãã¦ããã° j++ã ãã§äºè¶³ãã¾ããï¼ä¸ã®ä¾ã¯åºæ¬çã«j++ã°ã£ãããã¦ã¾ãï¼
ãããä¸è´ãã¦ããªããã°ããããããã«ã¯ããã¾ããã
ä¸è´ããªãã£ãæã¯ï¼ããè¨ç®ãç´ãã°æ£ããçãã¯å¾ããã¾ãããããã ã¨å¹çãæªããã¾ãã
ãããæ¢ã«è¨ç®ãããã®ãå©ç¨ãã¦ãªãã¨ãããã®ã whileã®é¨åãªã®ã§ããããj = A[j]ãã¨ããããªããã¼ãªãã¨ããã¦ãã¾ãã
ãã£ãã®ä¾ã¯åç´ãªä¾ã ã£ãã®ã§ãããå°ãè¤éãªä¾ãè¦ã¦ã¿ã¾ãããã
S : aabaabaaa A : _010123452 7 : _____j_i_ 8 : __j_____i
i=7,8ã®ã¨ãã ãpickupãã¾ããã
i ã 8 ã«ãªã£ãç¬é㯠j 㯠5 ã§ãwhileæã«å
¥ãã¾ãã
whileæã§ã¯ä»¥ä¸ã®ãããªæä½ãè¡ããã¾ãã
while (j >= 0 && S[i] != S[j]) j = A[j]; ã»i=8, j=5 ï¼ S[8]=a,S[5]=b ãªã®ã§ S[i] != [j]ãjãA[j](=2)ã«ãªãã ã»i=8, j=2 ï¼ S[8]=a,S[2]=b ãªã®ã§ S[i] != [j]ãjãA[j](=1)ã«ãªãã ã»i=8, j=1 ï¼ S[8]=a,S[1]=1 ãªã®ã§ S[i] == [j]ãwhileæãæãã¾ãã ï¼ã»whileæãæããå¾ j++ ãã㦠j = 2 ã¨ãªãã¾ããï¼
ãµã¼ãããªãã»ã©ï¼ï¼
çµå±ä½ããã¦ããã®ã§ããããã
åã®ã¹ãããã§ç·ã®é¨åãä¸è´ãã¦ããã¨ãã¾ããï¼äºæ®µç®ã®ç·ã®é¨å㯠S[0,A[i]-1]ï¼
赤ã®æåã¨éã®æåãåããªã j++ ã ãã§è¯ãããã§ããã
赤ã®æåã¨éã®æåãç°ãªãå ´åã次ã«ãã§ãã¯ãã¹ããã®ã¯ã
ãã®å³ã®ç·(æ¿ãæ¹)ã®é¨åã§ããã¤ã¾ããS[0,A[A[i]]-1]ã§ãã
ããã¾ã§ã®è¨ç®çµæãããç·ã®é¨åã¯ï¼ã¤ã¨ãä¸è´ãã¦ããã¯ãã§ããã
ããã§èµ¤ã®æåã¨é(æ¿ãæ¹)ã®æåãåããªãã° j = A[j], j++ ã¨ããã°ããã§ããã
ããã§ã赤ã®æåã¨éã®æåãç°ãªã£ã¦ããã°ä»åº¦ã¯ S[0,A[A[A[i]]]-1] ã«æ³¨ç®ãã¦ã»ã»ã»ã¨ãã£ã¦ããã°è¯ãã¨ããããã§ãã
ã¤ã¡ã¼ã¸ã§ãã¾ããã§ããããã
ããã§ãæ°ã«ãªãè¨ç®éã®æ¹ã§ããã
for (int i = 0; i < S.size(); i++) { while (j >= 0 && S[i] != S[j]) j = A[j]; j++; A[i+1] = j; }
ä¸è¦ï¼éã«ã¼ããªã®ã§O(|S|^2)ã£ã½ãè¦ãã¾ããã
j ã®å¤ã«æ³¨ç®ãã¦è§£æãã¦ã¿ã¾ããj ãå¤åããå ´æã¯ä»¥ä¸ã®ï¼ã«æã§ãã
ã»whileæãï¼ååã度㫠j ã¯å¿
ãæ¸ãã(ãã ã -1 ããå°ããã¯ãªããªã)
ã»foræãï¼ååã度㫠j++ ã«ãã j 㯠1 ãã¤å¢ããã
ãã㨠while ãåãåæ°ã£ã¦åè¨ã§é«ã
O(|S|) åã«ãªã£ã¦ãã¾ãããï¼ãªããªããj ã®å¤ãæ¸ããããã«ã¯ j ã®å¤ãå¢ãããªãã¨ãããªãã§ãããj ã®å¢å åã |S| ãããªãããã§ãã
ããããè¨ç®é解æãã¾ãã§ãããã¼ã
以ä¸ãMPã§ããã