Longest palindromic substrings: Difference between revisions
Content added Content deleted
Alextretyak (talk | contribs) (Added 11l) |
m (→{{header|Phix}}: added syntax colouring the hard way) |
||
Line 376: | Line 376: | ||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
{{trans|Raku}} |
|||
<lang Phix>function longest_palindromes(string s) |
|||
<!--<lang Phix>(phixonline)--> |
|||
-- s = lower/strip_spaces_and_punctuation/utf8_to_utf32, if rqd |
|||
<span style="color: #000080;font-style:italic;">-- demo/rosetta/Longest_palindromic_substrings.exw (plus two older versions)</span> |
|||
integer longest = 2 -- (do not treat length 1 as palindromic) |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
-- integer longest = 1 -- (do not treat length 0 as palindromic) [works just fine too] |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">longest_palindromes</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
sequence res = {} |
|||
<span style="color: #000080;font-style:italic;">-- s = lower/strip_spaces_and_punctuation/utf8_to_utf32, if rqd</span> |
|||
for i=1 to length(s) do |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">longest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- (do not treat length 1 as palindromic) |
|||
for e=length(s) to i+longest-1 by -1 do |
|||
-- integer longest = 1 -- (do not treat length 0 as palindromic) [works just fine too]</span> |
|||
if s[e]=s[i] then |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
string p = s[i..e] |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
integer lp = length(p) |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]?</span><span style="color: #000000;">2</span><span style="color: #0000FF;">:</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
if lp>=longest and p=reverse(p) then |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">rev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">,</span> |
|||
if lp>longest then |
|||
<span style="color: #000000;">fwd</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> |
|||
longest = lp |
|||
<span style="color: #008080;">while</span> <span style="color: #000000;">rev</span><span style="color: #0000FF;"><</span><span style="color: #000000;">i</span> <span style="color: #008080;">and</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">fwd</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">rev</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">fwd</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span> |
|||
res = {p} |
|||
<span style="color: #000000;">rev</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> |
|||
elsif not find(p,res) then -- (or just "else") |
|||
<span style="color: #000000;">fwd</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> |
|||
res = append(res,p) |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
end if |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">rev</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">fwd</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
end if |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">lp</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> |
|||
end if |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">lp</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">longest</span> <span style="color: #008080;">then</span> |
|||
end for |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">lp</span><span style="color: #0000FF;">></span><span style="color: #000000;">longest</span> <span style="color: #008080;">then</span> |
|||
end for |
|||
<span style="color: #000000;">longest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lp</span> |
|||
return res -- (or "sort(res)" or "unique(res)", as needed) |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">}</span> |
|||
end function |
|||
<span style="color: #008080;">elsif</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (or just "else")</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> |
|||
constant tests = {"babaccd","rotator","reverse","forever","several","palindrome","abaracadaraba"} |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
for i=1 to length(tests) do |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
printf(1,"%s: %v\n",{tests[i],longest_palindromes(tests[i])}) |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
end for</lang> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span> <span style="color: #000080;font-style:italic;">-- (or "sort(res)" or "unique(res)", as needed)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"babaccd"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"rotator"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"reverse"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"forever"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"several"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"palindrome"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"abaracadaraba"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"abbbc"</span><span style="color: #0000FF;">}</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s: %v\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">longest_palindromes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<!--</lang>--> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 413: | Line 422: | ||
palindrome: {} |
palindrome: {} |
||
abaracadaraba: {"aba","ara","aca","ada"} |
abaracadaraba: {"aba","ara","aca","ada"} |
||
abbbc: {"bbb"} |
|||
</pre> |
</pre> |
||
with longest initialised to 1, you get the same except for <code>palindrome: {"p","a","l","i","n","d","r","o","m","e"}</code> |
with longest initialised to 1, you get the same except for <code>palindrome: {"p","a","l","i","n","d","r","o","m","e"}</code> |
||
=== faster === |
|||
<lang Phix>function Manacher(string text) |
|||
-- Manacher's algorithm (linear time) |
|||
-- based on https://www.geeksforgeeks.org/manachers-algorithm-linear-time-longest-palindromic-substring-part-4 |
|||
-- but with a few tweaks, renames, and bugfixes (in particular the < (positions-1), which I later found LIJIE already said) |
|||
sequence res = {} |
|||
integer positions = length(text)*2+1 |
|||
if positions>1 then |
|||
sequence LPS = repeat(0,positions) |
|||
LPS[2] = 1 |
|||
integer centerPosition = 1, |
|||
centerRightPosition = 2, |
|||
maxLPSLength = 0 |
|||
for currentRightPosition=2 to positions-1 do |
|||
integer lcp = LPS[currentRightPosition+1], |
|||
diff = centerRightPosition - currentRightPosition |
|||
-- If currentRightPosition is within centerRightPosition |
|||
if diff >= 0 then |
|||
-- get currentLeftPosition iMirror for currentRightPosition |
|||
integer iMirror = 2*centerPosition-currentRightPosition + 1 |
|||
lcp = min(LPS[iMirror], diff) |
|||
end if |
|||
-- Attempt to expand palindrome centered at currentRightPosition |
|||
-- Here for odd positions, we compare characters and |
|||
-- if match then increment LPS Length by ONE |
|||
-- If even position, we just increment LPS by ONE without |
|||
-- any character comparison |
|||
while ((currentRightPosition + lcp) < (positions-1) and (currentRightPosition - lcp) > 0) and |
|||
((remainder(currentRightPosition+lcp+1, 2) == 0) or |
|||
(text[floor((currentRightPosition+lcp+1)/2)+1] == text[floor((currentRightPosition-lcp-1)/2)+1] )) do |
|||
lcp += 1 |
|||
end while |
|||
LPS[currentRightPosition+1] = lcp |
|||
maxLPSLength = max(lcp,maxLPSLength) |
|||
// If palindrome centered at currentRightPosition |
|||
// expand beyond centerRightPosition, |
|||
// adjust centerPosition based on expanded palindrome. |
|||
if (currentRightPosition + lcp) > centerRightPosition then |
|||
centerPosition = currentRightPosition |
|||
centerRightPosition = currentRightPosition + lcp |
|||
end if |
|||
end for |
|||
for p=1 to positions do |
|||
if LPS[p] = maxLPSLength then |
|||
integer start = floor((p-1 - maxLPSLength)/2) + 1, |
|||
finish = start + maxLPSLength - 1 |
|||
string r = text[start..finish] |
|||
if not find(r,res) then |
|||
res = append(res,r) |
|||
end if |
|||
end if |
|||
end for |
|||
end if |
|||
return res |
|||
end function |
|||
include mpfr.e |
|||
mpfr pi = mpfr_init(0,-10001) -- (set precision to 10,000 dp, plus the "3.") |
|||
mpfr_const_pi(pi) |
|||
string piStr = mpfr_sprintf("%.10000Rf", pi), |
|||
s = shorten(piStr) |
|||
printf(1,"%s: %v\n",{s,Manacher(piStr)})</lang> |
|||
{{out}} |
|||
(Same as above if given the same inputs.)<br> |
|||
However, while Manacher finishes 10,000 digits in 0s, longest_palindromes takes 1s for 2,000 digits, 15s for 5,000 digits, and 2 mins for 10,000 digits,<br> |
|||
which goes to prove that longest_palindromes() above is O(n<sup><small>2</small></sup>), whereas Manacher() is O(n).<br> |
|||
<pre> |
|||
3.141592653589793238...05600101655256375679 (10,002 digits): {"398989893","020141020"} |
|||
</pre> |
|||
Then again, this is also pretty fast (same output): |
|||
{{trans|Raku}} |
|||
<lang Phix>function longest_palindromes_raku(string s) |
|||
-- s = lower/strip_spaces_and_punctuation/utf8_to_utf32, if rqd |
|||
integer longest = 2 -- (do not treat length 1 as palindromic) |
|||
-- integer longest = 1 -- (do not treat length 0 as palindromic) [works just fine too] |
|||
sequence res = {} |
|||
for i=1 to length(s) do |
|||
for j=0 to iff(i>1 and s[i-1]=s[i]?2:1) do |
|||
integer rev = j, |
|||
fwd = 1 |
|||
while rev<i and i+fwd<=length(s) and s[i-rev]=s[i+fwd] do |
|||
rev += 1 |
|||
fwd += 1 |
|||
end while |
|||
string p = s[i-rev+1..i+fwd-1] |
|||
integer lp = length(p) |
|||
if lp>=longest then |
|||
if lp>longest then |
|||
longest = lp |
|||
res = {p} |
|||
elsif not find(p,res) then -- (or just "else") |
|||
res = append(res,p) |
|||
end if |
|||
end if |
|||
end for |
|||
end for |
|||
return res -- (or "sort(res)" or "unique(res)", as needed) |
|||
end function |
|||
printf(1,"%s: %v\n",{s,longest_palindromes_raku(piStr)}) |
|||
s = "abbbc" |
|||
printf(1,"%s: %v\n",{s,longest_palindromes_raku(s)})</lang> |
|||
{{out}} |
|||
(first line matches the above, the second was a initially a bug) |
|||
<pre> |
|||
3.141592653589793238...05600101655256375679 (10,002 digits): {"398989893","020141020"} |
|||
abbbc: {"bbb"} |
|||
</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |