Longitud del subarreglo común más largo para N arreglos dados

Dada una array 2-D array[][] que contiene N arrays, la tarea es encontrar el subarreglo común más largo (LCS) entre N arrays.

Ejemplos:

Entrada : N = 3, 
array[][] = { { 0, 1, 2, 3, 4 }, 
{ 2, 3, 4 }, 
{ 4, 0, 1, 2, 3 } }
Salida : 2
Explicación : El subcamino común más largo es {2, 3}.

Entrada : N = 2, 
array[][] = {{0, 1, 2, 3, 4}, 
{4, 3, 2, 1, 0}}
Salida : 1
Explicación : Los subtrayectos comunes más largos posibles son [0 ], [1], [2], [3] y [4]. Todos tienen una longitud de 1.

 

Enfoque: Está claro que la longitud de la LCS puede ser de búsqueda binaria . Es decir, si hay un subarreglo común con longitud L , siempre habrá un subarreglo común con una longitud menor que L. Por lo tanto, el marco de búsqueda binaria es el siguiente:

inferior = 0, superior = longitud máxima + 1; // LCS en [inferior, superior).
while (inferior + 1 < superior) {
   medio = (inferior + superior) / 2;
   if (hay alguna substring común con longitud media) {
       inferior = medio;
   } más{
       superior = medio;
   }
}
LCS = inferior;

Entonces, el punto clave aquí es verificar si hay algunos subconjuntos comunes con longitud media. Una forma habitual es adoptar Hashing, es decir, Rabin Karp Hashing .

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

El punto más conveniente aquí es que Hash(S[0…i]) puede usarse para calcular Hash(S[l…r]) en tiempo O(1) , con preparación O(N) . Eso es,

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

Por lo tanto, se pueden encontrar todos los valores hash de subarreglo con longitud media de dos arreglos dados y luego verificar si hay alguna superposición. Este procedimiento se puede realizar a través de Hash Table en O(|S|) o Set ( Balance Binary Search Tree ) en O(|S|log|S|). Por lo tanto, Binary Search + Hash puede resolver este problema en tiempo O(|S| log|S|). Siga los pasos a continuación para resolver este problema:

  • Inicialice la variable min_len con la máxima longitud posible, es decir, INT_MAX .
  • Itere sobre el rango [0, N) usando la variable i y realice las siguientes tareas:
    • Establezca el valor de min_len como el mínimo de min_len o array[i].size().
  • Inicialice las variables que comienzan como 0, terminan como min_len y mid como 0 para realizar la búsqueda binaria en la longitud.
  • Atraviese el ciclo while hasta que el inicio sea menor que el final y realice los siguientes pasos:
    • Establezca el valor de mid como el promedio de inicio y final.
    • Llame a la función check(array, mid) para verificar si la longitud mid es posible como respuesta o no usando el hash de Rabin-karp .
    • Si la función devuelve verdadero, establezca el valor de inicio como mid+1; de lo contrario, finalice como mid-1.
  • Después de realizar los pasos anteriores, imprima el valor de fin como respuesta.

A continuación se muestra la implementación del enfoque anterior.

C++

// C++ program for the above approach
#include <bits/stdc++.h>
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<vector<int> >& 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<vector<int> >& 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<vector<int> > 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<Long, Integer> freq = new HashMap<Long, Integer>();
    for (int i = 0; i < M; i++) {
      long curr_hash = 0, pow = 1;
      HashSet<Long> 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.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

Javascript

<script>
      // JavaScript Program to implement
      // the above approach
      let p = 1299827;
      let mod = 1e11 + 7;
      var M;
 
      // Function to implement rabin - carp
      // hashing to check whether the given length
      // is possible or not
      function check(array, len, M) {
          if (len == 0)
              return true;
          let freq = new Map();
 
          for (let i = 0; i < M; i++) {
              let curr_hash = 0, pow = 1;
              let found_hashes = new Set();
              for (let j = 0; j < len; j++) {
                  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 (let j = len; j < array[i].length; j++) {
                  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 (found_hashes.size != 0)
              {
                  var it = found_hashes.values();
               
                  // get first entry:
                  var first = it.next();
                   
                  // get value out of the iterator entry:
                  var h = first.value;
 
 
                  found_hashes.delete(h);
 
                  if (freq.has(h) == false) {
                      freq.set(h, 1)
                  }
                  else {
                      freq.set(h, freq.get(h) + 1)
                  }
 
                  if (freq.has(h) && freq.get(h) == M)
                      return true;
              }
          }
          return false;
      }
 
      // Function to find the longest common sub-array
      // from the given N arrays
      function longestCommonSubpath(N,
          array) {
 
          M = N;
 
          // Find the maximum length possible
          let minlen = Number.MAX_SAFE_INTEGER;
          for (let i = 0; i < array.length; i++) {
              minlen = Math.min(minlen, array[i].length);
          }
 
          // Binary search on the length
          let start = 0, end = minlen, mid = 0;
          while (start <= end) {
              let mid = Math.floor((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
      let arr = [[0, 1, 2, 3, 4],
      [2, 3, 4],
      [4, 0, 1, 2, 3]];
 
      let N = arr.length;
 
      document.write(longestCommonSubpath(N, arr));
 
  // This code is contributed by Potta Lokesh
  </script>
Producción

2

Complejidad de tiempo:  O(N*log(N))
Espacio auxiliar: O(N)

Publicación traducida automáticamente

Artículo escrito por sumitsingh32 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *