Наибольшая общая подстрока: различия между версиями

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
[непроверенная версия][отпатрулированная версия]
Содержимое удалено Содержимое добавлено
Реализация на C++: - улучшен код
подправил меню
Строка 39: Строка 39:
Очевидно, трудоемкость такого алгоритма составляет ''[[«O» большое и «o» малое|O]](mn)''.
Очевидно, трудоемкость такого алгоритма составляет ''[[«O» большое и «o» малое|O]](mn)''.


=== Реализация на C++ ===
==== Реализация на C++ ====
<source lang="cpp">
<source lang="cpp">
string
string
Строка 45: Строка 45:
{
{
string ret;
string ret;
int maxlen = 0, mi, mj;
int maxlen = 0, mi;
int **dt;
int **dt;
Строка 64: Строка 64:
maxlen = dt[i][j];
maxlen = dt[i][j];
mi = i;
mi = i;
mj = j;
}
}
}
}
Строка 78: Строка 77:
</source>
</source>


=== Реализация на C# ===
==== Реализация на C# ====
<!-- // в английской версии статьи
<!-- // в английской версии статьи
//http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Longest_common_substring
//http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Longest_common_substring
Строка 116: Строка 115:
</source>
</source>


=== Реализация на Haskell ===
==== Реализация на Haskell ====
<source lang="Haskell">
<source lang="Haskell">
import Data.List
import Data.List

Версия от 06:46, 7 января 2011

Наибольшая общая подстрока (longest common substring) — подстрока двух или более строк, имеющая максимальную длину.

Формально, наибольшей общей подстрокой строк называется строка , которая удовлетворяет условию , операция обозначает что строка является (возможно несобственной) подстрокой строки .

Алгоритмы поиска наибольшей общей подстроки

Наивный алгоритм

Решение задачи поиска наибольшей общей подстроки для двух строк и , длины которых и соответственно, заключается в заполнении таблицы размером по следующему правилу, принимая, что символы в строке нумеруются от единицы.

Максимальное число в таблице это и есть длина наибольшей общей подстроки, сама подстрока:

и .

В таблице заполнены значения для строк SUBSEQUENCE и SUBEUENCS:

   SUBSEQUENCE
  000000000000
S 010010000000
U 002000010000
B 000300000000
E 000001001001
U 001000010000
E 000001002001
N 000000000300
C 000000000040
S 010010000000

Получаем наибольшую общую подстроку UENC

Очевидно, трудоемкость такого алгоритма составляет O(mn).

Реализация на C++

string
LCS(const string& s1, const string& s2)
{
    string ret;
    int maxlen = 0, mi;
    int **dt;
    
    dt = new int*[s1.length() + 1];
    dt[0] = new int[s2.length() + 1];
    memset(dt[0], 0, (s2.length() + 1)*sizeof(int));
    for (int i = 1; i <= (int) s1.length(); ++i)
    {
        dt[i] = new int[s2.length() + 1];
        memset(dt[i], 0, (s2.length() + 1)*sizeof(int));
        for (int j = 1; j <= (int) s2.length(); ++j)
        {
            if (s1[i-1] == s2[j-1])
            {
                dt[i][j] = dt[i-1][j-1] + 1;
                if (maxlen < dt[i][j])
                {
                    maxlen = dt[i][j];
                    mi = i;
                }
            }
        }
        delete dt[i-1];
    }
    delete dt[s1.length()];
    delete dt;
    for (; maxlen > 0; --maxlen)
        ret = s1[--mi] + ret;
    return ret;
}

Реализация на C#

 public static int LongestCommonSubstring( string str1, string str2 )
    {
      if( String.IsNullOrEmpty( str1 ) || String.IsNullOrEmpty( str2 ) )
        return 0;

      List<int[]> num = new List<int[]>();
      int maxlen = 0;
      for( int i = 0; i < str1.Length; i++ )
      {
        num.Add( new int[ str2.Length ] );
        for( int j = 0; j < str2.Length; j++ )
        {
          if( str1[ i ] != str2[ j ] )
            num[ i ][ j ] = 0;
          else
          {
            if( ( i == 0 ) || ( j == 0 ) )
              num[ i ][ j ] = 1;
            else
              num[ i ][ j ] = 1 + num[ i - 1 ][ j - 1 ];
            if( num[ i ][ j ] > maxlen )
              maxlen = num[ i ][ j ];
          }
          if( i >= 2 )
            num[ i - 2 ] = null;
        }
      }
      return maxlen;
    }

Реализация на Haskell

import Data.List
import Data.Function

lcstr xs ys = maximumBy (compare `on` length) . concat $ [f xs' ys | xs' <- tails xs] ++ [f xs ys' | ys' <- drop 1 $ tails ys]
  where f xs ys = scanl g [] $ zip xs ys
        g z (x, y) = if x == y then z ++ [x] else []

Алгоритм, использующий суффиксное дерево

См. также