Let's represent the strings given to the girls by
and
. A pair of matching necklaces can be found as a concatenation of strings
and
such that
is a substring of
and
is a substring of
.

You might need to reverse
first. This converts the following case into the previous one.

2-approximation. As each necklace match consists of two substring matches, at least one of them has to be no shorter than half the length of the necklace. Let
be the length of the common suffix of
and
. Depending on if
,
is
or
. To find the longest common substring, we try all possible
and for each loop over
in increasing order calculating
from
. This takes
time,
extra memory.
and
. As we have seen, a necklace match can be decomposed into two substring matches by cutting the substrings that give the necklace match at some points. For each possible pair of cut points
(all pairs of indexes of
and
), we'll find the longest necklace that has these cut points. To find it, we can maximize length of the halves of the necklace separately. Let
be the length of longest suffix of
, that is a prefix of
. Similarly let
be the length of longest prefix of
that is a suffix of
. The longest necklace with cut points
has length
. To find
we can check all lengths naively in
, giving an
solution overall. Comparing equal length prefixes and suffixes with a rolling polynomial hash gives an
solution overall.
Full DP solution. To get a faster solution, we need to find
for many pairs of indexes at once. To do this, we will use
. If
then
,
, etc. Passing the length from
to
for all
is enough to calculate
. Doing this naively would take
time. We can optimize it by doing
for all
and then
for all
. This gives an
solution. To improve the memory usage to
you need to analyze the DP transitions carefully.
Full randomized solution. Choose a pair of indexes randomly. Extend
to
describing the longest substring match that
is part of. This takes time proportional to the length of the substring match. If the longest common substring has length
, then it takes on average
attempts to find it. So, this is a randomized
solution to finding the longest common substring.
To find necklaces, we'll generate substring matches this way. For a match of length
, we'll try to extend it with strings of length up to
to get a necklace match. We can check all lengths naively in
, giving an
solution. Using a rolling polynomial hash gives an
solution. The memory usage is
. This solution is on average faster than the DP solution.
Credits
- Task: Jakub Radoszewski (Poland)
- Solutions and tests: Oliver Nisumaa, Andres Unt (Estonia)
Comments