Наибольшая общая подстрока: различия между версиями
[отпатрулированная версия] | [непроверенная версия] |
Строка 7: | Строка 7: | ||
Решение задачи поиска наибольшей общей подстроки для двух строк <math>\left.s_1\right.</math> и <math>\left.s_2\right.</math>, длины которых <math>\left.m\right.</math> и <math>\left.n\right.</math> соответственно, заключается в заполнении таблицы <math>\left.A_{ij}\right.</math> размером <math>(m+1)\times (n+1)</math> по следующему правилу, принимая, что символы в строке нумеруются от единицы. |
Решение задачи поиска наибольшей общей подстроки для двух строк <math>\left.s_1\right.</math> и <math>\left.s_2\right.</math>, длины которых <math>\left.m\right.</math> и <math>\left.n\right.</math> соответственно, заключается в заполнении таблицы <math>\left.A_{ij}\right.</math> размером <math>(m+1)\times (n+1)</math> по следующему правилу, принимая, что символы в строке нумеруются от единицы. |
||
<math>\авыфолрфффафмм |
|||
<math>\left\{ |
|||
\begin{array}{rclr} |
\begin{array}{rclr} |
||
A_{0j}&=&0,&j=0\ldots n,\\ |
A_{0j}&=&0,&j=0\ldots n,\\ |
||
Строка 32: | Строка 32: | ||
'''E''' 00000'''1'''00'''2'''00'''1''' |
'''E''' 00000'''1'''00'''2'''00'''1''' |
||
'''N''' 000000000'''3'''00 |
'''N''' 000000000'''3'''00 |
||
'''C''' 0000000000< |
'''C''' 0000000000<fonмтиии рр ифвм |
||
'''S''' 0'''1'''00'''1'''0000000 |
'''S''' 0'''1'''00'''1'''0000000 |
||
Строка 44: | Строка 44: | ||
const int a_length = a.size(); |
const int a_length = a.size(); |
||
const int b_length = b.size(); |
const int b_length = b.size(); |
||
моо мваыф index = 0; |
|||
int max_length = 0; |
|||
int result_index = 0; |
|||
vector<int> solution(b_length + 1, 0); |
vector<int> solution(b_length + 1, 0); |
Версия от 15:08, 23 сентября 2011
Наибольшая общая подстрока (longest common substring) — подстрока двух или более строк, имеющая максимальную длину.
Формально, наибольшей общей подстрокой строк называется строка , которая удовлетворяет условию , операция обозначает что строка является (возможно несобственной) подстрокой строки .
Алгоритмы поиска наибольшей общей подстроки
Наивный алгоритм
Решение задачи поиска наибольшей общей подстроки для двух строк и , длины которых и соответственно, заключается в заполнении таблицы размером по следующему правилу, принимая, что символы в строке нумеруются от единицы.
Невозможно разобрать выражение (синтаксическая ошибка): {\displaystyle \авыфолрфффафмм \begin{array}{rclr} A_{0j}&=&0,&j=0\ldots n,\\ A_{i0}&=&0,&i=0\ldots m,\\ A_{ij}&=&0,&s_1[i] \ne s_2[j],i\ne 0, j\ne 0,\\ A_{ij}&=&A_{i-1j-1}+1,&s_1[i] = s_2[j],i\ne 0,j\ne 0. \end{array} \right. }
Максимальное число в таблице это и есть длина наибольшей общей подстроки, сама подстрока:
и .
В таблице заполнены значения для строк SUBSEQUENCE и SUBEUENCS:
SUBSEQUENCE 000000000000 S 010010000000 U 002000010000 B 000300000000 E 000001001001 U 001000010000 E 000001002001 N 000000000300 C 0000000000<fonмтиии рр ифвм S 010010000000 Получаем наибольшую общую подстроку UENC
Очевидно, трудоемкость такого алгоритма составляет O(mn).
Реализация на C++
void GetLargestCommonSubstring(string & result, const string & a, const string & b)
{
const int a_length = a.size();
const int b_length = b.size();
моо мваыф index = 0;
vector<int> solution(b_length + 1, 0);
for(int i = a_length - 1; i >= 0; i--)
{
const vector<int> prev_solution = solution;
for(int j = b_length - 1; j >= 0; j--)
{
if(a[i] != b[j])
solution[j] = 0;
else
{
const int length = 1 + prev_solution[j + 1];
if (length > max_length)
{
max_length = length;
result_index = i;
}
solution[j] = length;
}
}
}
result = a.substr(result_index, max_length);
}
Реализация на 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 []
Алгоритм, использующий суффиксное дерево
См. также
Это заготовка статьи по математике. Помогите Википедии, дополнив её. |