Here are some sequences:
'0.66666'
[3,0,1,2,2,2,0,1]
'banana'
'bandana'
'11221122'
I would like to find the index and length of the substring in each which is repeated (even if partially) for the most terms and which repeats until the end.
I wrote a function in JavaScript that successfully returns the expected output:
'0.66666' After occurring at index 2, '6' repeats for 4 terms.
[3,0,1,2,2,2,0,1] After occurring at index 1, [0,1,2,2,2] repeats for 2 terms.
'banana' After occurring at index 1, 'an' repeats for 3 terms.
'bandana' After occurring at index 4, 'an' repeats for 1 terms.
'11221122' After occurring at index 0, '1122' repeats for 4 terms.
Explanation:
[3,0,1,2,2,2,0,1]
is a sequence with 8 terms.[0,1,2,2,2]
is the longest substring which repeats at least partially to the end of the sequence, because after its first occurrence it repeats directly after for another 2 terms. Then the sequence terminates.- If we were to input
[3,0,2,2,2,0]
, you might think the substring[2]
wins because it repeats for 2 terms following its first occurrence, but it doesn't repeat to the end so the substring[0,2,2,2]
wins as the term that follows the only occurrence of this substring (0
) is also the first term in the substring meaning that it repeats for 1 term following the first occurance.
Repetition must continue to the end so for the second example [2,2,2]
is not valid though it also repeats for two terms
Here's the function (JS Bin):
function longestRepeatedSuffix(sequence) {
var repeatStart;
var blockLength;
var maxRepeatLength = 0;
// Go through each suffix from length 1 to the length of the sequence - 1.
suffixLoop: for (var suffixI = sequence.length - 1; suffixI > 0; suffixI--) {
var len = sequence.length - suffixI;
var repeatLength = 0;
// Go right to left through adjacent substrings the length of suffix.
// substringI may be negative on the last iteration.
for (var substringI = suffixI - len; substringI >= 1 - len; substringI -= len) {
// Go right to left through characters in the suffix and current substring.
for (var charI = len - 1; charI >= 0 && substringI + charI >= 0; charI--) {
// See how many characters match.
if (sequence[substringI + charI] === sequence[suffixI + charI]) {
repeatLength++;
if (repeatLength > maxRepeatLength) {
maxRepeatLength = repeatLength;
repeatStart = substringI + charI;
blockLength = len;
}
} else {
continue suffixLoop;
}
}
}
}
return 'After occurring at index ' + repeatStart + ', "' +
sequence.slice(repeatStart, repeatStart + blockLength) +
'" repeats for ' + maxRepeatLength + ' terms.';
}
I believe this is an O(n^2) implementation even though I used 3 nested for
-loops. So my question is: how can I use something like a suffix-tree to get even better time complexity?
Similar algorithm:
- Longest repeated substring: This is different, as it includes repetitions which overlap and those which are not adjacent (not just consecutive repetitions) and it doesn't require repetition to continue to the end.
bandana
thata
repeats 3 times? In one place you mention longest repeated substring. In other you mention you are looking for a substring that is repeated the most times. Those are two different problems. Which one are you dealing with? Also, what does it mean to "repeat until the end" or for "require repetition to continue to the end"? I don't understand what you mean by that. Please edit your question to clarify and make it internally self-consistent. $\endgroup$[3,0,1,2,2,2,0,1]
, why do you say that[0,1,2,2,2]
repeats 2 times? I see only one copy of it in the input. What do you mean by "terms"? I am assuming "terms" means "times"; have I misunderstood? $\endgroup$[0,1,2,2,2]
is a substring with 5 "terms" or characters. After the first occurrence of the substring, it is partially repeated for another 2 terms. $\endgroup$