Longest palindromic substrings: Difference between revisions

Added Easylang
(Added Easylang)
 
(44 intermediate revisions by 18 users not shown)
Line 6:
* [[Palindrome_detection]]
 
 
{{Template:Strings}}
<br><br>
 
=={{header|11l}}==
<syntaxhighlight lang="11l">F longest_palindrome(s)
V t = Array(‘^’s‘$’).join(‘#’)
V n = t.len
V p = [0] * n
V c = 0
V r = 0
L(i) 1 .< n - 1
p[i] = (r > i) & min(r - i, p[2 * c - i]) != 0
 
L t[i + 1 + p[i]] == t[i - 1 - p[i]]
p[i]++
 
I i + p[i] > r
(c, r) = (i, i + p[i])
 
V (max_len, center_index) = max(enumerate(p).map((i, n) -> (n, i)))
R s[(center_index - max_len) I/ 2 .< (center_index + max_len) I/ 2]
 
L(s) [‘three old rotators’,
‘never reverse’,
‘stable was I ere I saw elbatrosses’,
‘abracadabra’,
‘drome’,
‘the abbatial palace’]
print(‘'’s‘' -> '’longest_palindrome(s)‘'’)</syntaxhighlight>
 
{{out}}
<pre>
'three old rotators' -> 'rotator'
'never reverse' -> 'ever reve'
'stable was I ere I saw elbatrosses' -> 'table was I ere I saw elbat'
'abracadabra' -> 'ada'
'drome' -> 'e'
'the abbatial palace' -> 'abba'
</pre>
 
=={{header|Action!}}==
<syntaxhighlight lang="action!">BYTE FUNC Palindrome(CHAR ARRAY s)
BYTE l,r
 
l=1 r=s(0)
WHILE l<r
DO
IF s(l)#s(r) THEN RETURN (0) FI
l==+1 r==-1
OD
RETURN (1)
 
PROC Find(CHAR ARRAY text,res)
BYTE first,len
len=text(0)
WHILE len>0
DO
FOR first=1 TO text(0)-len+1
DO
SCopyS(res,text,first,first+len-1)
IF Palindrome(res) THEN
RETURN
FI
OD
len==-1
OD
res(0)=0
RETURN
 
PROC Test(CHAR ARRAY text)
CHAR ARRAY res(100)
 
Find(text,res)
PrintF("""%S"" -> ""%S""%E",text,res)
RETURN
 
PROC Main()
Test("three old rotators")
Test("never reverse")
Test("abracadabra")
Test("the abbatial palace")
Test("qwertyuiop")
Test("")
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Longest_palindromic_substrings.png Screenshot from Atari 8-bit computer]
<pre>
"three old rotators" -> "rotator"
"never reverse" -> "ever reve"
"abracadabra" -> "aca"
"the abbatial palace" -> "abba"
"qwertyuiop" -> "q"
"" -> ""
</pre>
 
=={{header|ALGOL 68}}==
Palindromes of length 1 or more are detected, finds the left most palindrome if there are several of the same length.<br>
Treats upper and lower case as distinct and does not require the characters to be letters.
<syntaxhighlight lang="algol68">BEGIN # find the longest palindromic substring of a string #
# returns the length of s #
OP LENGTH = ( STRING s )INT: ( UPB s + 1 ) - LWB s;
# returns s right-padded with blanks to at least w characters or s if it is already wide enough #
PRIO PAD = 1;
OP PAD = ( STRING s, INT w )STRING:
BEGIN
STRING result := s;
WHILE LENGTH result < w DO result +:= " " OD;
result
END # PAD # ;
# returns the longest palindromic substring of s #
# if there are multiple substrings with the longest length, the leftmost is returned #
PROC longest palindromic substring = ( STRING s )STRING:
IF LENGTH s < 2
THEN s
ELSE
INT lwb s = LWB s;
INT upb s = UPB s;
STRING result := s[ lwb s ];
IF s[ lwb s + 1 ] = s[ lwb s ] THEN
# the first two characters are a palindrome #
result +:= s[ lwb s + 1 ]
FI;
FOR i FROM lwb s + 1 TO upb s - 1 DO
INT p start := i;
INT p end := i + 1;
IF IF s[ i - 1 ] = s[ i + 1 ] THEN
# odd length palindrome at i - 1 #
p start -:= 1;
TRUE
ELIF s[ i ] = s[ i + 1 ] THEN
# even length palindrome at i #
TRUE
ELSE FALSE
FI
THEN
# have a palindrome at p start : p end #
# attempt to enlarge the range #
WHILE IF p start = lwb s OR p end = upb s
THEN FALSE
ELSE s[ p start - 1 ] = s[ p end + 1 ]
FI
DO # can extend he palindrome #
p start -:= 1;
p end +:= 1
OD;
IF ( p end + 1 ) - p start > LENGTH result
THEN
# have a longer palindrome #
result := s[ p start : p end ]
FI
FI
OD;
result
FI # longest palindromic substring # ;
# finds the longest palindromic substring of s and checks it is the expacted value #
PROC test = ( STRING s, expected value )VOID:
BEGIN
STRING palindrome = longest palindromic substring( s );
print( ( ( """" + s + """" ) PAD 38, " -> ", ( """" + palindrome + """" ) PAD 36
, IF palindrome = expected value THEN "" ELSE " NOT " + expected value + " ???" FI
, newline
)
)
END # test longest palindromic substring # ;
test( "three old rotators", "rotator" );
test( "never reverse", "ever reve" );
test( "stable was I ere I saw elbatrosses", "table was I ere I saw elbat" );
test( "abracadabra", "aca" );
test( "drome", "d" );
test( "x", "x" );
test( "the abbatial palace", "abba" );
test( "", "" );
test( "abcc", "cc" );
test( "abbccc", "ccc" )
END</syntaxhighlight>
{{out}}
<pre>
"three old rotators" -> "rotator"
"never reverse" -> "ever reve"
"stable was I ere I saw elbatrosses" -> "table was I ere I saw elbat"
"abracadabra" -> "aca"
"drome" -> "d"
"x" -> "x"
"the abbatial palace" -> "abba"
"" -> ""
"abcc" -> "cc"
"abbccc" -> "ccc"
</pre>
 
=={{header|Arturo}}==
{{trans|Nim}}
<syntaxhighlight lang="rebol">palindrome?: function [str]-> str = join reverse split str
 
lps: function [s][
maxLength: 0
result: new []
loop 0..dec size s 'fst [
loop fst..dec size s 'lst [
candidate: slice s fst lst
if palindrome? candidate [
if? maxLength < size candidate [
result: new @[candidate]
maxLength: size candidate
]
else [
if maxLength = size candidate ->
'result ++ candidate
]
]
]
]
 
return (maxLength > 1)? -> result
-> []
]
 
loop ["babaccd", "rotator", "several", "palindrome", "piété", "tantôt", "étêté"] 'str [
palindromes: lps str
print [str "->" (0 < size palindromes)? -> join.with:", " palindromes
-> "X"]
]</syntaxhighlight>
 
{{out}}
 
<pre>babaccd -> bab, aba
rotator -> rotator
several -> eve
palindrome -> X
piété -> été
tantôt -> tôt
étêté -> étêté</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">LPS(str){
found := [], result := [], maxL := 0
while (StrLen(str) >= 2 && StrLen(str) >= maxL){
s := str
loop {
while (SubStr(s, 1, 1) <> SubStr(s, 0)) ; while 1st chr <> last chr
s := SubStr(s, 1, StrLen(s)-1) ; trim last chr
if (StrLen(s) < 2 || StrLen(s) < maxL )
break
if (s = reverse(s)){
found.Push(s)
maxL := maxL < StrLen(s) ? StrLen(s) : maxL
break
}
s := SubStr(s, 1, StrLen(s)-1) ; trim last chr
}
str := SubStr(str, 2) ; trim 1st chr and try again
}
maxL := 0
for i, str in found
maxL := maxL < StrLen(str) ? StrLen(str) : maxL
for i, str in found
if (StrLen(str) = maxL)
result.Push(str)
return result
}
reverse(s){
for i, v in StrSplit(s)
output := v output
return output
}</syntaxhighlight>
Examples:<syntaxhighlight lang="autohotkey">db =
(
three old rotators
never reverse
stable was I ere I saw elbatrosses
abracadabra
drome
x
the abbatial palace
)
 
for i, line in StrSplit(db, "`n", "`r"){
result := "[""", i := 0
for i, str in LPS(line)
result .= str """, """
output .= line "`t> " Trim(result, """, """) (i?"""":"") "]`n"
}
MsgBox % output
return</syntaxhighlight>
{{out}}
<pre>three old rotators > ["rotator"]
never reverse > ["ever reve"]
stable was I ere I saw elbatrosses > ["table was I ere I saw elbat"]
abracadabra > ["aca", "ada"]
drome > []
x > []
the abbatial palace > ["abba"]
</pre>
 
=={{header|EasyLang}}==
<syntaxhighlight>
func$ reverse s$ .
a$[] = strchars s$
for i = 1 to len a$[] div 2
swap a$[i] a$[len a$[] - i + 1]
.
return strjoin a$[]
.
func palin s$ .
if s$ = reverse s$
return 1
.
return 0
.
func$ lpali st$ .
for n = 1 to len st$ - 1
for m = n + 1 to len st$
sub$ = substr st$ n (m - n)
if palin sub$ = 1
if len sub$ > len max$
max$ = sub$
.
.
.
.
return max$
.
for s$ in [ "three old rotators" "never reverse" "stable was I ere I saw elbatrosses" "abracadabra" "drome" "the abbatial palace" ]
print lpali s$
.
</syntaxhighlight>
{{out}}
<pre>
rotator
ever reve
table was I ere I saw elbat
aca
d
abba
</pre>
 
=={{header|F_Sharp|F#}}==
===Manacher Function===
<syntaxhighlight lang="fsharp">
// Manacher Function. Nigel Galloway: October 1st., 2020
let Manacher(s:string) = let oddP,evenP=Array.zeroCreate s.Length,Array.zeroCreate s.Length
let rec fN i g e (l:int[])=match g>=0 && e<s.Length && s.[g]=s.[e] with true->l.[i]<-l.[i]+1; fN i (g-1) (e+1) l |_->()
let rec fGo n g Ʃ=match Ʃ<s.Length with
false->oddP
|_->if Ʃ<=g then oddP.[Ʃ]<-min (oddP.[n+g-Ʃ]) (g-Ʃ)
fN Ʃ (Ʃ-oddP.[Ʃ]-1) (Ʃ+oddP.[Ʃ]+1) oddP
match (Ʃ+oddP.[Ʃ])>g with true->fGo (Ʃ-oddP.[Ʃ]) (Ʃ+oddP.[Ʃ]) (Ʃ+1) |_->fGo n g (Ʃ+1)
let rec fGe n g Ʃ=match Ʃ<s.Length with
false->evenP
|_->if Ʃ<=g then evenP.[Ʃ]<-min (evenP.[n+g-Ʃ]) (g-Ʃ)
fN Ʃ (Ʃ-evenP.[Ʃ]) (Ʃ+evenP.[Ʃ]+1) evenP
match (Ʃ+evenP.[Ʃ])>g with true->fGe (Ʃ-evenP.[Ʃ]+1) (Ʃ+evenP.[Ʃ]) (Ʃ+1) |_->fGe n g (Ʃ+1)
(fGo 0 -1 0,fGe 0 -1 0)
</syntaxhighlight>
 
===The Task===
<syntaxhighlight lang="fsharp">
let fN g=if g=[||] then (0,0) else g|>Array.mapi(fun n g->(n,g))|>Array.maxBy snd
let lpss s=let n,g=Manacher s in let n,g=fN n,fN g in if (snd n)*2+1>(snd g)*2 then s.[(fst n)-(snd n)..(fst n)+(snd n)] else s.[(fst g)-(snd g)+1..(fst g)+(snd g)]
let test = ["three old rotators"; "never reverse"; "stable was I ere I saw elbatrosses"; "abracadabra"; "drome"; "the abbatial palace"; ""]
test|>List.iter(fun n->printfn "A longest palindromic substring of \"%s\" is \"%s\"" n (lpss n))
</syntaxhighlight>
{{out}}
<pre>
A longest palindromic substring of "three old rotators" is "rotator"
A longest palindromic substring of "never reverse" is "ever reve"
A longest palindromic substring of "stable was I ere I saw elbatrosses" is "table was I ere I saw elbat"
A longest palindromic substring of "abracadabra" is "aca"
A longest palindromic substring of "drome" is "d"
A longest palindromic substring of "the abbatial palace" is "abba"
A longest palindromic substring of "" is ""
</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="vbnet">Function isPalindrome(s As String) As Integer
For i As Integer = 1 To Len(s) / 2
If Mid(s, i, 1) <> Mid(s, Len(s) - i + 1, 1) Then Return False
Next i
Return True
End Function
 
Sub LongestPalindrome(s As String)
Dim As String substr, longest = ""
Dim As Integer i, j
For i = 1 To Len(s)
For j = i To Len(s)
substr = Mid(s, i, j - i + 1)
If isPalindrome(substr) Andalso Len(substr) > Len(longest) Then longest = substr
Next j
Next i
Print "The longest palindromic substring is/are: "
For i = 1 To Len(s)
For j = i To Len(s)
substr = Mid(s, i, j - i + 1)
If IsPalindrome(substr) Andalso Len(substr) = Len(longest) Andalso Len(substr) > 2 Then Print substr; " ";
Next j
Next i
If Len(longest) <= 2 Then Print "<no palindromic substring of two of more letters found>"
End Sub
 
Dim s As String
Input "Enter a string: ", s
 
LongestPalindrome(s)
 
Sleep</syntaxhighlight>
 
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 76 ⟶ 483:
fmt.Printf(" %-13s Length %d -> %v\n", s, len(longest[0]), longest)
}
}</langsyntaxhighlight>
 
{{out}}
Line 89 ⟶ 496:
abaracadaraba Length 3 -> [aba aca ada ara]
</pre>
 
=={{header|Haskell}}==
A list version, written out of curiosity. A faster approach could be made with an indexed datatype.
 
<syntaxhighlight lang="haskell">-------------- LONGEST PALINDROMIC SUBSTRINGS ------------
 
longestPalindromes :: String -> ([String], Int)
longestPalindromes [] = ([], 0)
longestPalindromes s = go $ palindromes s
where
go xs
| null xs = (return <$> s, 1)
| otherwise = (filter ((w ==) . length) xs, w)
where
w = maximum $ length <$> xs
 
palindromes :: String -> [String]
palindromes = fmap go . palindromicNuclei
where
go (pivot, (xs, ys)) =
let suffix = fmap fst (takeWhile (uncurry (==)) (zip xs ys))
in reverse suffix <> pivot <> suffix
 
palindromicNuclei :: String -> [(String, (String, String))]
palindromicNuclei =
concatMap go .
init . tail . ((zip . scanl (flip ((<>) . return)) []) <*> scanr (:) [])
where
go (a@(x:_), b@(h:y:ys))
| x == h = [("", (a, b))]
| otherwise =
[ ([h], (a, y : ys))
| x == y ]
go _ = []
 
 
--------------------------- TEST -------------------------
main :: IO ()
main =
putStrLn $
fTable
"Longest palindromic substrings:\n"
show
show
longestPalindromes
[ "three old rotators"
, "never reverse"
, "stable was I ere I saw elbatrosses"
, "abracadabra"
, "drome"
, "the abbatial palace"
, ""
]
 
------------------------ FORMATTING ----------------------
fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
fTable s xShow fxShow f xs =
unlines $
s : fmap (((++) . rjust w ' ' . xShow) <*> ((" -> " ++) . fxShow . f)) xs
where
rjust n c = drop . length <*> (replicate n c ++)
w = maximum (length . xShow <$> xs)</syntaxhighlight>
{{Out}}
<pre>Longest palindromic substrings:
 
"three old rotators" -> (["rotator"],7)
"never reverse" -> (["ever reve"],9)
"stable was I ere I saw elbatrosses" -> (["table was I ere I saw elbat"],27)
"abracadabra" -> (["aca","ada"],3)
"drome" -> (["d","r","o","m","e"],1)
"the abbatial palace" -> (["abba"],4)
"" -> ([],0)</pre>
 
=={{header|jq}}==
'''Adapted from [[#Wren]]'''
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq">def longestPalindromicSubstring:
length as $len
| if $len <= 1 then .
else explode as $s
| {targetLen: $len, longest: [], i: 0}
| until(.stop;
(.i + .targetLen - 1) as $j
| if $j < $len
then $s[.i:$j+1] as $ss
| if $ss == ($ss|reverse) then .longest += [$ss] else . end
| .i += 1
else
if .longest|length > 0 then .stop=true else . end
| .i = 0
| .targetLen += - 1
end )
| .longest
| map(implode)
| unique
end ;
def strings:
["babaccd", "rotator", "reverse", "forever", "several", "palindrome", "abaracadaraba"];
 
"The palindromic substrings having the longest length are:",
(strings[]
| longestPalindromicSubstring as $longest
| " \(.): length \($longest[0]|length) -> \($longest)"
)</syntaxhighlight>
 
{{out}}
<pre>
The palindromic substrings having the longest length are:
babaccd: length 3 -> ["aba","bab"]
rotator: length 7 -> ["rotator"]
reverse: length 5 -> ["rever"]
forever: length 5 -> ["rever"]
several: length 3 -> ["eve"]
palindrome: length 1 -> ["a","d","e","i","l","m","n","o","p","r"]
abaracadaraba: length 3 -> ["aba","aca","ada","ara"]
</pre>
 
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">function allpalindromics(s)
list, len = String[], length(s)
for i in 1:len-1, j in i+1:len
Line 108 ⟶ 634:
join(list[findall(x -> length(x) == length(list[end]), list)], "\" or \""), "\"")
end
</langsyntaxhighlight>{{out}}
<pre>
The longest palindromic substring of babaccd is: "bab" or "aba"
Line 119 ⟶ 645:
 
===Manacher algorithm===
<langsyntaxhighlight lang="julia">
function manacher(str)
s = "^" * join(split(str, ""), "#") * "\$"
Line 144 ⟶ 670:
"The longest palindromic substring of $teststring is: \"$pal\"")
end
</langsyntaxhighlight>{{out}}
<pre>
The longest palindromic substring of babaccd is: "aba"
Line 155 ⟶ 681:
</pre>
 
=={{header|PhixMathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[ExpandSubsequenceTry, LongestPalindromicSubsequence]
<lang Phix>function longest_palindromes(string s)
ExpandSubsequenceTry[seq_List, beginpos : {a_, b_}] :=
-- s = lower/strip_spaces_and_punctuation/utf8_to_utf32, if rqd
Module[{len, maxbroaden, last},
integer longest = 2 -- (do not treat length 1 as palindromic)
len = Length[seq];
-- integer longest = 1 -- (do not treat length 0 as palindromic) [works just fine too]
maxbroaden = Min[a - 1, len - b];
sequence res = {}
last = maxbroaden;
for i=1 to length(s) do
Do[
for e=length(s) to i+longest-1 by -1 do
If[! PalindromeQ[Take[seq, {a - j, b + j}]],
if s[e]=s[i] then
last = j - 1;
string p = s[i..e]
Break[];
integer lp = length(p)
]
if lp>=longest and p=reverse(p) then
,
if lp>longest then
{j, maxbroaden}
longest = lp
];
res = {p}
{a - last, b + last}
elsif not find(p,res) then -- (or just "else")
]
res = append(res,p)
LongestPalindromicSubsequence[l_List] :=
end if
Module[{evenposs, oddposs, subseqs},
end if
evenposs = SequencePosition[l, {x_, x_}];
end if
oddposs = SequencePosition[l, {x_, y_, x_}];
end for
subseqs = Join[evenposs, oddposs];
end for
subseqs = ExpandSubsequenceTry[l, #] & /@ subseqs;
return res -- (or "sort(res)" or "unique(res)", as needed)
If[Length[subseqs] > 0,
end function
TakeLargestBy[Take[l, #] & /@ subseqs, Length, 1][[1]]
,
{}
]
]
StringJoin@LongestPalindromicSubsequence[Characters["three old rotators"]]
StringJoin@LongestPalindromicSubsequence[Characters["never reverse"]]
StringJoin@LongestPalindromicSubsequence[Characters["stable was I ere I saw elbatrosses"]]
StringJoin@LongestPalindromicSubsequence[Characters["abracadabra"]]
StringJoin@LongestPalindromicSubsequence[Characters["drome"]]
StringJoin@LongestPalindromicSubsequence[Characters["the abbatial palace"]]</syntaxhighlight>
{{out}}
<pre>"rotator"
"ever reve"
"table was I ere I saw elbat"
"aca"
""
"abba"</pre>
 
=={{header|Nim}}==
Simple algorithm but working on Unicode code points.
<syntaxhighlight lang="nim">import sequtils, strutils, unicode
 
func isPalindrome(s: seq[Rune]): bool =
## Return true if a sequence of runes is a palindrome.
for i in 1..(s.len shr 1):
if s[i - 1] != s[^i]:
return false
result = true
 
func lps(s: string): seq[string] =
var maxLength = 0
var list: seq[seq[Rune]]
let r = s.toRunes
for first in 0..r.high:
for last in first..r.high:
let candidate = r[first..last]
if candidate.isPalindrome():
if candidate.len > maxLength:
list = @[candidate]
maxLength = candidate.len
elif candidate.len == maxLength:
list.add candidate
if maxLength > 1:
result = list.mapIt($it)
 
for str in ["babaccd", "rotator", "several", "palindrome", "piété", "tantôt", "étêté"]:
let result = lps(str)
if result.len == 0:
echo str, " → ", "<no palindromic substring of two of more letters found>"
else:
echo str, " → ", result.join(", ")</syntaxhighlight>
 
{{out}}
constant tests = {"babaccd","rotator","reverse","forever","several","palindrome","abaracadaraba"}
<pre>babaccd → bab, aba
for i=1 to length(tests) do
rotator → rotator
printf(1,"%s: %v\n",{tests[i],longest_palindromes(tests[i])})
several → eve
end for</lang>
palindrome → <no palindromic substring of two of more letters found>
piété → été
tantôt → tôt
étêté → étêté</pre>
 
=={{header|Pascal}}==
==={{header|Free Pascal}}===
<syntaxhighlight lang="pascal">
program FindLongestPalindrome;
 
uses
SysUtils,strutils;
 
const
arr: array of string = ('three old rotators', 'never reverse', 'stable was I ere I saw elbatrosses', 'abracadabra', 'drome', 'the abbatial palace', '');
 
var
st, longestPalindrome, dummy: string;
i, j, longest: integer;
 
begin
for st in arr do
begin
longest := 0;
longestPalindrome := '';
for i := 1 to Length(st) do
begin
for j := Length(st) downto i do
begin
dummy := Copy(st, i, j - i + 1);
if (j - i + 1 > longest) and (dummy = ReverseString(dummy)) then
begin
longest := j - i + 1;
longestPalindrome := dummy;
end;
end;
end;
WriteLn(Format('%-35s -> %s', [st, longestPalindrome]));
end;
end.
 
</syntaxhighlight>
{{out}}
<pre>
three old rotators -> rotator
never reverse -> ever reve
stable was I ere I saw elbatrosses -> table was I ere I saw elbat
abracadabra -> aca
drome -> d
the abbatial palace -> abba
->
</pre>
 
=={{header|Perl}}==
The short one - find all palindromes with one regex.
<syntaxhighlight lang="perl">use strict;
use warnings;
 
print "Longest Palindrome For $_ = @{[ longestpalindrome($_) ]}\n"
for qw(babaccd rotator reverse forever several palindrome abaracadabra);
 
sub longestpalindrome
{
my @best = {"''" => 0};
pop =~ /(.+) .? (??{reverse $1}) (?{ $best[length $&]{$&}++ }) (*FAIL)/x;
keys %{pop @best};
}</syntaxhighlight>
{{out}}
<pre>
Longest Palindrome For babaccd = aba bab
Longest Palindrome For rotator = rotator
Longest Palindrome For reverse = rever
Longest Palindrome For forever = rever
Longest Palindrome For several = eve
Longest Palindrome For palindrome = ''
Longest Palindrome For abaracadabra = aba ara aca ada
</pre>
 
The faster one - does the million digits of Pi in under half a second.
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'bitwise';
 
#@ARGV = 'pi.dat'; # uncomment to use this file or add filename to command line
 
my $forward = lc do { local $/; @ARGV ? <> : <DATA> };
$forward =~ s/\W+//g;
 
my $range = 10;
my $backward = reverse $forward;
my $length = length $forward;
my @best = {"''" => 0};
my $len;
for my $i ( 1 .. $length - 2 )
{
do
{
my $right = substr $forward, $i, $range;
my $left = substr $backward, $length - $i, $range;
( $right ^. $left ) =~ /^\0\0+/ and # evens
($len = 2 * length $&) >= $#best and
$best[ $len ]{substr $forward, $i - length $&, $len}++;
( $right ^. "\0" . $left ) =~ /^.(\0+)/ and # odds
($len = 1 + 2 * length $1) >= $#best and
$best[ $len ]{substr $forward, $i - length $1, $len}++;
} while $range < $#best and $range = $#best;
}
print "Longest Palindrome ($#best) : @{[ keys %{ $best[-1] } ]}\n";
 
__DATA__
this data borrowed from raku...
 
Never odd or even
Was it a car or a cat I saw?
Too bad I hid a boot
I, man, am regal - a German am I
toot
Warsaw was raw</syntaxhighlight>
{{out}}
<pre>
Longest Palindrome (27) : ootimanamregalagermanamitoo
</pre>
 
=={{header|Phix}}==
{{trans|Raku}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo/rosetta/Longest_palindromic_substrings.exw (plus two older versions)</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<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>
<span style="color: #000080;font-style:italic;">-- s = lower/strip_spaces_and_punctuation/utf8_to_utf32, if rqd</span>
<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)
-- integer longest = 1 -- (do not treat length 0 as palindromic) [works just fine too]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</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;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<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>
<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>
<span style="color: #000000;">fwd</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<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>
<span style="color: #000000;">rev</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">fwd</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<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>
<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>
<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>
<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>
<span style="color: #000000;">longest</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lp</span>
<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>
<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>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<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>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 193 ⟶ 932:
palindrome: {}
abaracadaraba: {"aba","ara","aca","ada"}
abbbc: {"bbb"}
</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>
 
=== 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
integer rev = iff(i>1 and s[i-1]=s[i]?1:0),
fwd = 0
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
return res -- (or "sort(res)" or "unique(res)", as needed)
end function
 
printf(1,"%s: %v\n",{s,longest_palindromes_raku(piStr)})</lang>
 
=={{header|Python}}==
Line 304 ⟶ 942:
(This version ignores case but allows non-alphanumerics).
<langsyntaxhighlight lang="python">'''Longest palindromic substrings'''
 
 
Line 313 ⟶ 951:
the given string, tupled with the
maximal length.
Non -alphanumerics are included here.
'''
k = s.lower()
Line 328 ⟶ 966:
] if palindromes else list(s),
maxLength
) if s else ([], 0)
 
 
Line 357 ⟶ 995:
iEnd = len(s) - 1
 
def plimit(ij):
i, j = ij
return 0 == i or iEnd == j or s[i-1] != s[j+1]
Line 366 ⟶ 1,004:
 
def go(ij):
ab = until(plimit)(expansion)(ij)
return s[ab[0]:ab[1] + 1]
return go
Line 383 ⟶ 1,021:
'stable was I ere I saw elbatrosses',
'abracadabra',
'drome',
'the abbatial palace',
''
])
)
Line 434 ⟶ 1,075:
# MAIN ---
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{Out}}
<pre>Longest palindromic substrings:
Line 441 ⟶ 1,082:
'never reverse' -> (['ever reve'], 9)
'stable was I ere I saw elbatrosses' -> (['table was i ere i saw elbat'], 27)
'abracadabra' -> (['aca', 'ada'], 3)</pre>
'drome' -> (['d', 'r', 'o', 'm', 'e'], 1)
'the abbatial palace' -> (['abba'], 4)
'' -> ([], 0)</pre>
 
=={{header|Raku}}==
{{works with|Rakudo|2020.09}}
This version regularizes (ignores) case and ignores non alphabeticalphanumeric characters. It is only concerned with finding the ''longest'' palindromic substrings so does not exhaustively find ''all possible'' palindromes. If a palindromic substring is found to be part of a longer palindrome, it is not captured separately. Showing the longest 5 palindromic substring groups. Run it with no parameters to operate on the default; pass in a file name to run it against that instead.
 
<syntaxhighlight lang="raku" perl6line>my @chars = ( @*ARGS[0] ?? @*ARGS[0].IO.slurp !! q:to/ENDBOB/ ) .lc.comb: /\w/;
Lyrics to "Bob" copyright Weird Al Yankovic
https://www.youtube.com/watch?v=JUQDzj6R3p4
Line 492 ⟶ 1,136:
God! A red nugget! A fat egg under a dog!
Go hang a salami, I'm a lasagna hog!
ENDBOB
#"
 
my @cpfoa; = flat
(1 ..^ @chars).race(:1000batch).map: -> \idx {
 
my @s;
for ^@chars -> $i {
myfor ($rev1,$fwd) =2 0, 0;{
++$rev if $i andmy @chars[int ($irev, -$fwd) 1]= eq @chars[$i]_, 1;
loop {
quietly last if ($rev > $iidx) or $rev and|| (@chars[$iidx - $rev] ne @chars[$iidx + $fwd]);
++ $rev = $rev + 1;
++ $fwd = $fwd + 1;
}
@s.push: @chars[idx - $rev ^..^ idx + $fwd].join if $rev + $fwd > 2;
last if @chars[idx - 1] ne @chars[idx];
}
next unless +@s;
@cpfoa[(my $pal = @chars[$i - $rev ^..^ $i + $fwd].join).chars].push: $pal if $rev + $fwd > 2;
@s
}
 
"{.key} ({+.value})\t{.value.unique.sort}".put for @cpfoa.grepclassify( *.sochars ).tailsort( -*.key ).head(5);</langsyntaxhighlight>
{{out}}
Returns the length, (the count) and the list:
<pre>doninemeninterpretninemeninod godarednuggetafateggunderadog</pre>
<pre>29 (2) doninemeninterpretninemeninod godarednuggetafateggunderadog
26 (1) gohangasalamiimalasagnahog
23 (1) arwontloversrevoltnowra
21 (4) imanamregalagermanami mayamoodybabydoomayam ootnolemonsnomelontoo oozyratinasanitaryzoo
20 (1) ratsliveonnoevilstar
</pre>
 
This isn't particularlyintensively optimised but isn't too shabby either. When run against the first million digits of pi: [httphttps://www.eveanderssongithub.com/pithundergnat/digitsrc/1000000 http:blob/master/www.eveandersson.comresouces/pi/digits/.txt 1000000], anddigits modifyingof thepi lasttext linefile] to(Pass returnin the topfile fivepath/name longestat palindromethe groups <pre>.unique.sort.put for @cpfoa.grep( *.socommand line).tail(5).reverse;</pre> Wewe get:
 
<pre>13 (1) 9475082805749
12 (1) 450197791054
11 (8) 04778787740 09577577590 21348884312 28112721182 41428782414 49612121694 53850405835 84995859948
10 (9) 0045445400 0136776310 1112552111 3517997153 5783993875 6282662826 7046006407 7264994627 8890770988
9 (98) 019161910 020141020 023181320 036646630 037101730 037585730 065363560 068363860 087191780 091747190 100353001 104848401 111262111 131838131 132161231 156393651 160929061 166717661 182232281 193131391 193505391 207060702 211878112 222737222 223404322 242424242 250171052 258232852 267919762 272636272 302474203 313989313 314151413 314424413 318272813 323212323 330626033 332525233 336474633 355575553 357979753 365949563 398989893 407959704 408616804 448767844 450909054 463202364 469797964 479797974 480363084 489696984 490797094 532121235 546000645 549161945 557040755 559555955 563040365 563828365 598292895 621969126 623707326 636414636 636888636 641949146 650272056 662292266 667252766 681565186 684777486 712383217 720565027 726868627 762727267 769646967 777474777 807161708 819686918 833303338 834363438 858838858 866292668 886181688 895505598 896848698 909565909 918888819 926676629 927202729 929373929 944525449 944848449 953252359 972464279 975595579 979202979 992868299</pre>
in slightlyright morearound than 157 seconds on my system.
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program finds and displays the longest palindromic string(s) in a given string. */
parse arg s /*obtain optional argument from the CL.*/
if s=='' | s=="," then s= 'babaccd rotator reverse forever several palindrome abaracadaraba'
/* [↑] the case of strings is respected*/
do i=1 for words(s); say x= word(s, i) /*searchobtain eacha ofstring theto be (S)examined. strings. */
xL= wordlength(s, ix); L m= length(x)0 /*get athe string's tolength; beSet examinedmax & lengthlen.*/
do LL=2 for L-1 /*start with palindromes of length two.*/
m= 0
if do LL=2 for L-find(1) then m= max(m, LL) /*Found a palindrome? Set /*start with palindromes ofM=new length two.*/
end if find(1) then m= max(m,LL) /*Found a palindrom? Set M=new length.LL*/
LL= max(1, m)
end /*LL*/
call find 0 /*find all palindromes with length LL.*/
LL= max(1,m)
say ' longest palindromic substrings for string: ' x
call find .
say '────────────────────────────────────────────'copies('─', 2 + L)
say ' longest palindromic substrings for string: ' x
do n=1 for words(@) /*show longest palindromic substrings. */
say '────────────────────────────────────────────'copies('─', 2 + L)
say ' do n (length=1'LL") for" words word(@, n) /*display a " /*show longest palindromic substringssubstring. */
end /*n*/; say; ' say (length='LL") " /*display word(@,a n)two─blank separation fence.*/
end end /*ni*/
say
end /*i*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
find: parse arg short /*if SHORT==1, only find 1 palendromepalindrome.*/
@= /*initialize palindrome list to a null.*/
do j=1 for L-LL+1; $= substr(x, j, LL) /*obtain length ofa possible palindromespalindromic substr.*/
if $\= substr=reverse(x,$) j, LL)then iterate /*Not a palindrome? /*obtain a possibleThen palindromicskip substrit.*/
@= @ $ if $\==reverse($) then iterate /*Not a palindrome? Then skip it. /*add a palindromic substring to a list*/
if short then @=return @1 $ /*we have found one palindrome. /*add a palindromic substring to a list*/
end /*j*/; return 0 if short==1 then return 1 /*have found" one " palindrome. " some palindrome(s). */</syntaxhighlight>
end /*j*/; return 0 /* " " some palindrome(s). */</lang>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 604 ⟶ 1,255:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
load "stdlib.ring"
 
Line 633 ⟶ 1,284:
see "Longest palindromic substrings:" + nl
see resList
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 648 ⟶ 1,299:
 
The Phix entry examples have been used.
<langsyntaxhighlight ecmascriptlang="wren">import "./seq" for Lst
import "./fmt" for Fmt
 
var longestPalSubstring = Fn.new { |s|
Line 676 ⟶ 1,327:
var longest = Lst.distinct(longestPalSubstring.call(s))
Fmt.print(" $-13s Length $d -> $n", s, longest[0].count, longest)
}</langsyntaxhighlight>
 
{{out}}
1,969

edits