Longest Common Extension / LCE (Introduction and Naive Method)
Last Updated :
31 Jan, 2023
The Longest Common Extension (LCE) problem considers a string s and computes, for each pair (L , R), the longest sub string of s that starts at both L and R. In LCE, in each of the query we have to answer the length of the longest common prefix starting at indexes L and R.
Example:
String : “abbababba”
Queries: LCE(1, 2), LCE(1, 6) and LCE(0, 5)
Find the length of the Longest Common Prefix starting at index given as, (1, 2), (1, 6) and (0, 5).
The string highlighted “green” are the longest common prefix starting at index- L and R of the respective queries. We have to find the length of the longest common prefix starting at index- (1, 2), (1, 6) and (0, 5).
Algorithm (Naive Method)
- For each of the LCE queries of the form – LCE(L, R) do the following:
- Initialise the LCE ‘length’ as 0
- Start comparing the prefix starting from index- L and R character by character.
- If the characters matches, then this character is in our Longest Common Extension. So increment ‘length’ (length++).
- Else if the characters mismatch, then return this ‘length’.
- The returned ‘length’ will be the required LCE(L, R).
Implementation :
Below is C++ implementation of above Naive algorithm.
CPP
#include<bits/stdc++.h>
using namespace std;
struct Query
{
int L, R;
};
int LCE(string str, int n, int L, int R)
{
int length = 0;
while (str[L+length] == str[R+length] &&
R+length < n)
length++;
return (length);
}
void LCEQueries(string str, int n, Query q[],
int m)
{
for ( int i=0; i<m; i++)
{
int L = q[i].L;
int R = q[i].R;
printf ( "LCE (%d, %d) = %d\n" , L, R,
LCE(str, n, L, R));
}
return ;
}
int main()
{
string str = "abbababba" ;
int n = str.length();
Query q[] = {{1, 2}, {1, 6}, {0, 5}};
int m = sizeof (q)/ sizeof (q[0]);
LCEQueries(str, n, q, m);
return (0);
}
|
Java
import java.util.*;
class GFG
{
static class Query
{
int L, R;
Query( int L, int R)
{
this .L = L;
this .R = R;
}
};
static int LCE(String str, int n, int L, int R)
{
int length = 0 ;
while ( R + length < n && str.charAt(L + length) == str.charAt(R + length))
length++;
return (length);
}
static void LCEQueries(String str, int n, Query q[],
int m)
{
for ( int i = 0 ; i < m; i++)
{
int L = q[i].L;
int R = q[i].R;
System.out.printf( "LCE (%d, %d) = %d\n" , L, R,
LCE(str, n, L, R));
}
return ;
}
public static void main(String[] args)
{
String str = "abbababba" ;
int n = str.length();
Query q[] = new Query[ 3 ];
q[ 0 ] = new Query( 1 , 2 );
q[ 1 ] = new Query( 1 , 6 );
q[ 2 ] = new Query ( 0 , 5 );
int m = q.length;
LCEQueries(str, n, q, m);
}
}
|
Python3
def LCE(string, n, L, R):
length = 0
while (R + length < n and string[L + length] = = string[R + length]):
length + = 1
return length
def LCEQueries(string, n, queries):
for query in queries:
L = query[ 0 ]
R = query[ 1 ]
print ( "LCE ({}, {}) = {}" . format (L, R, LCE(string, n, L, R)))
if __name__ = = '__main__' :
string = "abbababba"
n = len (string)
queries = [( 1 , 2 ), ( 1 , 6 ), ( 0 , 5 )]
LCEQueries(string, n, queries)
|
C#
using System;
public class GFG
{
public
class Query
{
public
int L, R;
public
Query( int L, int R)
{
this .L = L;
this .R = R;
}
};
static int LCE(String str, int n, int L, int R)
{
int length = 0;
while ( R + length < n && str[L + length] == str[R + length])
length++;
return (length);
}
static void LCEQueries(String str, int n, Query []q,
int m)
{
for ( int i = 0; i < m; i++)
{
int L = q[i].L;
int R = q[i].R;
Console.WriteLine( "LCE (" + L + ", " + R +
") = " + LCE(str, n, L, R));
}
return ;
}
public static void Main(String[] args)
{
String str = "abbababba" ;
int n = str.Length;
Query []q = new Query[3];
q[0] = new Query(1, 2);
q[1] = new Query(1, 6);
q[2] = new Query (0, 5);
int m = q.Length;
LCEQueries(str, n, q, m);
}
}
|
Javascript
<script>
class Query
{
constructor(L,R)
{
this .L = L;
this .R = R;
}
}
function LCE(str,n,L,R)
{
let length = 0;
while ( R + length < n && str[L + length] == str[R + length])
length++;
return (length);
}
function LCEQueries(str,n,q,m)
{
for (let i = 0; i < m; i++)
{
let L = q[i].L;
let R = q[i].R;
document.write( "LCE (" +L+ ", " +R+ ") = " +LCE(str, n, L, R)+ "<br>" );
}
return ;
}
let str = "abbababba" ;
let n = str.length;
let q = new Array(3);
q[0] = new Query(1, 2);
q[1] = new Query(1, 6);
q[2] = new Query (0, 5);
let m = q.length;
LCEQueries(str, n, q, m);
</script>
|
Output
LCE (1, 2) = 1
LCE (1, 6) = 3
LCE (0, 5) = 4
Analysis of Naive Method :
Time Complexity: The time complexity is O(Q.N), where
- Q = Number of LCE Queries
- N = Length of the input string
One may be surprised that the although having a greater asymptotic time complexity, the naive method outperforms other efficient method(asymptotically) in practical uses. We will be discussing this in coming sets on this topic.
Auxiliary Space: O(1), in-place algorithm.
Applications:
- K-Mismatch Problem->Landau-Vishkin uses LCE as a subroutine to solve k-mismatch problem
- Approximate String Searching.
- Palindrome Matching with Wildcards.
- K-Difference Global Alignment.
In the next sets we will discuss how LCE (Longest Common Extension) problem can be reduced to a RMQ (Range Minimum Query). We will also discuss more efficient methods to find the longest common extension.
Share your thoughts in the comments
Please Login to comment...