Hledání nejdelšího podřetězce palindromu

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 16. července 2020; kontroly vyžadují 2 úpravy .

V informatice je nejdelším palindromickým podřetězcem  problém najít nejdelší podřetězec daného řetězce, kterým je palindrom .. Například nejdelší palindromický podřetězec „banánu“ je „anana“. Nejdelší palindromický podřetězec není nutně jedinečný; například v řetězci "abracadabra" není žádný palindromický podřetězec delší než tři znaky, ale existují řetězce skládající se přesně ze tří znaků, a to "aka" a "ada". Některé aplikace chtějí najít všechny maximální palindromické podřetězce (jmenovitě všechny podřetězce, které jsou samy palindromy a nelze je doplnit delšími palindromickými podřetězci) namísto vracení pouze jednoho podřetězce nebo vracení maximální délky palindromického podřetězce.

Manacher (1975 ) vynalezl časově lineární algoritmus pro výčet všech palindromů na začátku daného řetězce. Jak však ukázali Apostolico, Breslauer & Galil (1995 ), stejný algoritmus lze použít k nalezení všech nejdelších palindromických podřetězců kdekoli v daném řetězci, opět v lineárním čase. Proto poskytuje řešení problému nalezení maximálního palindromického podřetězce v lineárním čase. Alternativní řešení lineárního času navrhli Jeuring (1994 ) a Gusfield (1997 ), kteří popsali řešení založené na použití příponových stromů . Jsou také známy účinné paralelní algoritmy pro řešení tohoto problému. [jeden]

Problém nalezení nejdelší palindromické podřetězce by neměl být zaměňován s problémem nalezení nejdelší palindromické podsekvence .

Manažerův algoritmus

K nalezení nejdelšího palindromu v řetězci v lineárním čase může algoritmus použít následující vlastnosti palindromů a subpalindromů:

  1. Levá strana palindromu je zrcadlovým obrazem jeho pravé strany.
  2. (Případ 1) Třetí palindrom, jehož střed leží na pravé straně prvního palindromu, bude mít přesně stejnou délku jako druhý palindrom, jehož střed je zrcadlen na levou stranu, pokud druhý palindrom leží uvnitř prvního palindromu a vzdaluje se od hranice v bodě alespoň pro jednu postavu.
  3. (Případ 2) Pokud má druhý palindrom společnou hranici s prvním palindromem nebo ji přesahuje, pak je zaručeno, že délka třetího palindromu nebude menší než vzdálenost od jeho středu k pravému okraji prvního palindromu. Tato délka je vzdálenost od středu druhého palindromu k levému znaku prvního palindromu.
  4. Abychom našli délku třetího palindromu v případě 2, je nutné porovnat znaky následující za znakem úplně vpravo prvního palindromu s jejich zrcadlovým obrazem kolem středu třetího palindromu, dokud není řetězec vyčerpán nebo nerovnost znaky jsou nalezeny.
  5. (Případ 3) První ani druhý palindrom neposkytuje informace pro určení délky čtvrtého palindromu, jehož střed leží mimo hranici prvního palindromu.
  6. Proto je pro určení palindromických délek podřetězců v řetězci zleva doprava žádoucí mít referenční palindrom (fungující jako první palindrom), jehož znaky zaujímají v řetězci pozice úplně vpravo (a tedy třetí palindrom v případě 2). a čtvrtý palindrom v případě 3 může nahradit první palindrom, aby se stal novým referenčním palindromem).
  7. Pokud jde o odhad času pro určení palindromické délky pro každý znak řetězce: v případě 1 se neprovádí žádné porovnání znaků, v případech 2 a 3 jsou kandidáty na znak pouze znaky řetězce ležící za znakem zcela vpravo referenčního palindromu. srovnání (a proto Případ 3 vždy vede ke změně referenčního palindromu, když Případ 2 změní referenční palindrom pouze v případě, že se ukáže, že délka třetího palindromu je ve skutečnosti větší než jeho slíbená minimální délka).
  8. U palindromů sudého stupně leží střed mezi dvěma středovými symboly palindromu.

Implementace

Nechat:

Výsledek: Nejdelší palindrom nebo první znak řetězce

#include <řetězec> #include <vektor> pomocí jmenného prostoru std ; string longestPalindrome ( const string & s ){ vektor < char > s2 ( velikost s . () * 2 + 1 , '#' ); //vytvoří pseudo-řetězec s hranicemi '#' pro ( int i = 0 ; i != s . velikost (); ++ i ){ s2 [ i * 2 + 1 ] = s [ i ]; } intp [ s2 . _ velikost ()]; int r , c , index , i_mir ; int maxLen = 1 ; i_mir = index = r = c = 0 ; for ( int i = 1 ; i != s2 . velikost ( ) - 1 ; ++ i ){ i_mir = 2 * c - i ; //Pokud spadáme do poloměru předchozího výsledku, //pak lze počáteční hodnotu aktuálního poloměru vzít ze zrcadleného výsledku p [ i ] = r > i ? min ( p [ i_mir ], r - i ) : 0 ; while ( i > p [ i ] && ( i + p [ i ] + 1 ) < s2 . velikost () && s2 [ i - p [ i ] - 1 ] == s2 [ i + p [ i ] + 1 ] ) ++ p [ i ]; if ( p [ i ] + i > r ){ c = i ; r = i + p [ i ]; } if ( maxLen < p [ i ]){ maxLen = p [ i ]; index = i ; } } //Namapujte nalezené pozice na původní řetězec return s . substr (( index - maxLen ) / 2 , maxLen ); }

Poznámky

  1. Crochemore & Rytter (1991 ), Apostolico, Breslauer & Galil (1995 ).

Literatura

Odkazy

Tento článek zahrnuje text z Longest palindromického podřetězce na PEGWiki pod licencí Creative Commons Attribution ( CC-BY-3.0 ).