Longest palindromic substrings: Difference between revisions

Content added Content deleted
(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}}==