 GeeksforGeeks App
Open App Browser
Continue

# Length of longest common subarray for given N arrays

Given a 2-D array array[][] containing N arrays, the task is to find the longest common subarray(LCS) among N arrays.

Examples:

Input: N = 3,
array[][] = { { 0, 1, 2, 3, 4 },
{ 2, 3, 4 },
{ 4, 0, 1, 2, 3 } }
Output: 2
Explanation: The longest common subpath is {2, 3}.

Input: N = 2,
array[][] = {{0, 1, 2, 3, 4},
{4, 3, 2, 1, 0}}
Output: 1
Explanation: The possible longest common subpaths are , , , , and . All have a length of 1.

Approach: It is clear that the length of the LCS can be binary search. That is, if there is a common sub-array with length L, there will always be a common sub-array with a length less than L. Therefore, the binary search framework is as follows:

lower = 0, upper = maxlength + 1; // LCS in [lower, upper).
while (lower + 1 < upper) {
middle = (lower + upper) / 2;
if (there is some common substring with length middle) {
lower = middle;
} else{
upper = middle;
}
}
LCS = lower;

So, the key point here is to check whether there are some common sub-arrays with length middle. A usual way is to adopt Hashing i.e, Rabin Karp Hashing.

Hash(S[0..n-1]) = (S[n-1] * MAGIC^0 + S[n-2] * MAGIC^1 + .. + S[n-1-i] * MAGIC^i + … ) % MOD

The most convenient point here is that Hash(S[0…i]) can be used to calculate the Hash(S[l…r]) in O(1) time, with O(N) preparation. That is,

Hash(S[l..r]) = (Hash(S[0..r]) – Hash(S[0..l-1]) * MAGIC^(r-l+1)) % MOD

Therefore, all hash values of sub-array with length middle from two given arrays can be found, and then, check whether there is any overlap. This procedure can be done via Hash Table in O(|S|) or Set (Balanced Binary Search Tree) in O(|S|log|S|). Therefore, Binary Search + Hash can solve this problem in O(|S| log|S|) time. Follow the steps below to solve this problem:

• Initialize the variable min_len as maximum length possible i.e, INT_MAX.
• Iterate over the range [0, N) using the variable i and perform the following tasks:
• Set the value of min_len as the minimum of min_len or array[i].size().
• Initialize the variables start as 0, end as min_len, and mid as 0 to perform the binary search on the length.
• Traverse over the while loop till start is less than equal to end and perform the following steps:
• Set the value of mid as the average of start and end.
• Call the function check(array, mid) to check if the length mid is possible as the answer or not using Rabin-karp hashing.
• If the function returns true, then set the value of start as mid+1 otherwise end as mid-1.
• After performing the above steps, print the value of end as the answer.

Below is the implementation of the above approach

## C++

 `// C++ program for the above approach``#include ``using` `namespace` `std;` `const` `long` `long` `p = 1299827;``const` `long` `long` `mod = 1e11 + 7;``long` `long` `M;` `// Function to implement rabin - carp``// hashing to check whether the given length``// is possible or not``bool` `check(vector >& array, ``int` `len)``{``    ``if` `(len == 0)``        ``return` `true``;``    ``map<``long` `long``, ``int``> freq;``    ``for` `(``int` `i = 0; i < M; i++) {``        ``long` `long` `curr_hash = 0, ``pow` `= 1;``        ``set<``long` `long``> found_hashes;``        ``for` `(``int` `j = 0; j < len; j++) {``            ``curr_hash = (curr_hash * p) % mod;``            ``curr_hash += array[i][j];``            ``if` `(j != len - 1)``                ``pow` `= (``pow` `* p) % mod;``        ``}``        ``found_hashes.insert(curr_hash);``        ``for` `(``int` `j = len; j < array[i].size(); j++) {``            ``curr_hash += mod;``            ``curr_hash -= (array[i][j - len] * ``pow``) % mod;``            ``curr_hash %= mod;``            ``curr_hash = curr_hash * p;``            ``curr_hash %= mod;``            ``curr_hash += array[i][j];``            ``curr_hash %= mod;``            ``found_hashes.insert(curr_hash);``        ``}``        ``while` `(found_hashes.size()) {``            ``long` `long` `h = *(found_hashes.begin());``            ``found_hashes.erase(found_hashes.begin());``            ``freq[h]++;``            ``if` `(freq[h] == M)``                ``return` `true``;``        ``}``    ``}``    ``return` `false``;``}` `// Function to find the longest common sub-array``// from the given N arrays``int` `longestCommonSubpath(``long` `long` `N,``                         ``vector >& array)``{` `    ``M = N;` `    ``// Find the maximum length possible``    ``int` `minlen = INT_MAX;``    ``for` `(``int` `i = 0; i < array.size(); i++) {``        ``minlen = min(minlen, (``int``)array[i].size());``    ``}` `    ``// Binary search on the length``    ``int` `start = 0, end = minlen, mid = 0;``    ``while` `(start <= end) {``        ``int` `mid = (start + end) / 2;` `        ``// Function Call to check whether``        ``// it is possible or not``        ``if` `(check(array, mid)) {``            ``start = mid + 1;``        ``}``        ``else` `{``            ``end = mid - 1;``        ``}``    ``}``    ``return` `end;``}` `// Driver Code``int` `main()``{``    ``vector > arr{ { 0, 1, 2, 3, 4 },``                              ``{ 2, 3, 4 },``                              ``{ 4, 0, 1, 2, 3 } };` `    ``long` `long` `N = arr.size();` `    ``cout << longestCommonSubpath(N, arr);` `    ``return` `0;``}`

## Java

 `// Java program for the above approach``import` `java.util.HashMap;``import` `java.util.HashSet;` `class` `GFG {` `  ``static` `long` `p = ``1299827``;``  ``static` `long` `mod = (``long``) 1E11 + ``7``;``  ``static` `long` `M;` `  ``// Function to implement rabin - carp``  ``// hashing to check whether the given length``  ``// is possible or not``  ``static` `boolean` `check(``int``[][] array, ``int` `len) {``    ``if` `(len == ``0``)``      ``return` `true``;``    ``HashMap freq = ``new` `HashMap();``    ``for` `(``int` `i = ``0``; i < M; i++) {``      ``long` `curr_hash = ``0``, pow = ``1``;``      ``HashSet found_hashes = ``new` `HashSet();``      ``for` `(``int` `j = ``0``; j < len; j++) {``        ``curr_hash = (curr_hash * p) % mod;``        ``curr_hash += array[i][j];``        ``if` `(j != len - ``1``)``          ``pow = (pow * p) % mod;``      ``}``      ``found_hashes.add(curr_hash);``      ``for` `(``int` `j = len; j < array[i].length; j++) {``        ``curr_hash += mod;``        ``curr_hash -= (array[i][j - len] * pow) % mod;``        ``curr_hash %= mod;``        ``curr_hash = curr_hash * p;``        ``curr_hash %= mod;``        ``curr_hash += array[i][j];``        ``curr_hash %= mod;``        ``found_hashes.add(curr_hash);``      ``}``      ``while` `(found_hashes.size() > ``0``) {``        ``long` `h = found_hashes.iterator().next();``        ``found_hashes.remove(h);``        ``if` `(freq.containsKey(h)) {``          ``freq.put(h, freq.get(h) + ``1``);``        ``} ``else` `{``          ``freq.put(h, ``1``);``        ``}``        ``if` `(freq.get(h) == M)``          ``return` `true``;``      ``}``    ``}``    ``return` `false``;``  ``}` `  ``// Function to find the longest common sub-array``  ``// from the given N arrays``  ``public` `static` `int` `longestCommonSubpath(``long` `N, ``int``[][] array) {` `    ``M = N;` `    ``// Find the maximum length possible``    ``int` `minlen = Integer.MAX_VALUE;``    ``for` `(``int` `i = ``0``; i < array.length; i++) {``      ``minlen = Math.min(minlen, (``int``) array[i].length);``    ``}` `    ``// Binary search on the length``    ``int` `start = ``0``, end = minlen, mid = ``0``;``    ``while` `(start <= end) {``      ``mid = (start + end) / ``2``;` `      ``// Function Call to check whether``      ``// it is possible or not``      ``if` `(check(array, mid)) {``        ``start = mid + ``1``;``      ``} ``else` `{``        ``end = mid - ``1``;``      ``}``    ``}``    ``return` `end;``  ``}` `  ``// Driver Code``  ``public` `static` `void` `main(String args[]) {``    ``int``[][] arr = { { ``0``, ``1``, ``2``, ``3``, ``4` `}, { ``2``, ``3``, ``4` `}, { ``4``, ``0``, ``1``, ``2``, ``3` `} };` `    ``long` `N = arr.length;` `    ``System.out.println(longestCommonSubpath(N, arr));``  ``}``}` `// This code is contributed by gfgking.`

## Python3

 `# Python Program to implement``# the above approach``p ``=` `1299827``mod ``=` `1e11` `+` `7``M ``=` `None` `# Function to implement rabin - carp``# hashing to check whether the given length``# is possible or not``def` `check(array, _len, M):``    ``if` `(_len ``=``=` `0``):``        ``return` `True``    ``freq ``=` `{}` `    ``for` `i ``in` `range``(M):``        ``curr_hash ``=` `0``        ``pow` `=` `1``        ``found_hashes ``=` `set``()``        ``for` `j ``in` `range``(_len):``            ``curr_hash ``=` `(curr_hash ``*` `p) ``%` `mod``            ``curr_hash ``=` `curr_hash ``+` `array[i][j]``            ``if` `(j !``=` `_len ``-` `1``):``                ``pow` `=` `(``pow` `*` `p) ``%` `mod` `        ``found_hashes.add(curr_hash)``        ``for` `j ``in` `range``(_len, ``len``(array[i])):``            ``curr_hash ``=` `curr_hash ``+` `mod``            ``curr_hash ``=` `curr_hash ``-` `(array[i][j ``-` `_len] ``*` `pow``) ``%` `mod``            ``curr_hash ``=` `curr_hash ``%` `mod``            ``curr_hash ``=` `curr_hash ``*` `p``            ``curr_hash ``=` `curr_hash ``%` `mod``            ``curr_hash ``=` `curr_hash ``+` `array[i][j]``            ``curr_hash ``=` `curr_hash ``%` `mod``            ``found_hashes.add(curr_hash)``        ``while` `(``len``(found_hashes) !``=` `0``):``            ``it ``=` `list``(found_hashes)` `            ``# get first entry:``            ``h ``=` `it[``0``]``            ``found_hashes.remove(h)` `            ``if` `(h ``not` `in` `freq):``                ``freq[h] ``=` `1``            ``else``:``                ``freq[h] ``+``=` `1` `            ``if` `(h ``in` `freq ``and` `freq[h] ``=``=` `M):``                ``return` `True``    ``return` `False` `# Function to find the longest common sub-array``# from the given N arrays``def` `longestCommonSubpath(N, array):``    ``M ``=` `N` `    ``# Find the maximum length possible``    ``minlen ``=` `10` `*``*` `9``    ``for` `i ``in` `range``(``len``(array)):``        ``minlen ``=` `min``(minlen, ``len``(array[i]))` `    ``# Binary search on the length``    ``start ``=` `0``    ``end ``=` `minlen``    ``mid ``=` `0``    ``while` `(start <``=` `end):``        ``mid ``=` `(start ``+` `end) ``/``/` `2` `        ``# Function Call to check whether``        ``# it is possible or not``        ``if` `(check(array, mid, M)):``            ``start ``=` `mid ``+` `1``        ``else``:``            ``end ``=` `mid ``-` `1``    ``return` `end` `# Driver Code``arr ``=` `[[``0``, ``1``, ``2``, ``3``, ``4``], [``2``, ``3``, ``4``], [``4``, ``0``, ``1``, ``2``, ``3``]]` `N ``=` `len``(arr)``print``(longestCommonSubpath(N, arr))` `# This code is contributed by Saurabh Jaiswal`

## C#

 `using` `System;``using` `System.Collections.Generic;` `class` `GFG {` `    ``static` `long` `p = 1299827;``    ``static` `long` `mod = (``long``)1E11 + 7;``    ``static` `long` `M;` `    ``// Function to implement rabin - carp``    ``// hashing to check whether the given length``    ``// is possible or not``    ``static` `bool` `check(``int``[][] array, ``int` `len) {``        ``if` `(len == 0)``            ``return` `true``;``        ``var` `freq = ``new` `Dictionary<``long``, ``int``>();``        ``for` `(``int` `i = 0; i < M; i++) {``            ``long` `curr_hash = 0, pow = 1;``            ``var` `found_hashes = ``new` `HashSet<``long``>();``            ``for` `(``int` `j = 0; j < len; j++) {``                ``curr_hash = (curr_hash * p) % mod;``                ``curr_hash += array[i][j];``                ``if` `(j != len - 1)``                    ``pow = (pow * p) % mod;``            ``}``            ``found_hashes.Add(curr_hash);``            ``for` `(``int` `j = len; j < array[i].Length; j++) {``                ``curr_hash += mod;``                ``curr_hash -= (array[i][j - len] * pow) % mod;``                ``curr_hash %= mod;``                ``curr_hash = curr_hash * p;``                ``curr_hash %= mod;``                ``curr_hash += array[i][j];``                ``curr_hash %= mod;``                ``found_hashes.Add(curr_hash);``            ``}``            ``while` `(found_hashes.Count > 0) {``                ``long` `h = found_hashes.GetEnumerator().Current;``                ``found_hashes.Remove(h);``                ``if` `(freq.ContainsKey(h)) {``                    ``freq[h] += 1;``                ``}``                ``else` `{``                    ``freq[h] = 1;``                ``}``                ``if` `(freq[h] == M)``                    ``return` `true``;``            ``}``        ``}``        ``return` `false``;``    ``}` `    ``// Function to find the longest common sub-array``    ``// from the given N arrays``    ``public` `static` `int` `longestCommonSubpath(``long` `N, ``int``[][] array) {` `        ``M = N;` `        ``// Find the maximum length possible``        ``int` `minlen = ``int``.MaxValue;``        ``for` `(``int` `i = 0; i < array.Length; i++) {``            ``minlen = Math.Min(minlen, array[i].Length);``        ``}` `        ``// Binary search on the length``        ``int` `start = 0, end = minlen, mid = 0;``        ``while` `(start <= end) {``            ``mid = (start + end) / 2;` `            ``// Function Call to check whether``            ``// it is possible or not``            ``if` `(check(array, mid)) {``                ``start = mid + 1;``            ``} ``else` `{``                ``end = mid - 1;``            ``}``        ``}``        ``return` `end - 1;``    ``}``    ``static` `void` `Main(``string``[] args) {``        ``int``[][] arr = {``            ``new` `int``[] { 0, 1, 2, 3, 4 },``            ``new` `int``[] { 2, 3, 4 },``            ``new` `int``[] { 4, 0, 1, 2, 3 }``        ``};` `        ``long` `N = arr.Length;` `        ``Console.WriteLine(longestCommonSubpath(N, arr));``        ``Console.ReadKey();``    ``}``}`

## Javascript

 ``

Output

`2`

Time Complexity:  O(N*log(N))
Auxiliary Space: O(N)

My Personal Notes arrow_drop_up