нахождении набольшей общей последователности (LCS)

mikron
Дата: 10.07.2017 17:17:40
Многим надеюсь известна задача о нахождении набольшей общей последователности aka "Longest Common Sequence".
У меня стоит схожая задача но с допонителным ограничением, что должна выдерживатся минималныя длина подпоследователности.
Другими словами если рассматривать 2 последовательности:

1: AGCAGCAGC
2: AGAGAC
то стандартный LCS: |AGAGAC| = 6

Если же внисти ограничение на мин длину подпоследователности = 2
то результат будет уже другой:
1: AG(C)AG(CAGC)
2: AG AG(AC)

|AGAG| = 4

Меня интересует в первуй очередь длинна этой последовательности.
кто видит/знает эфективный алгоритм нахождения этой длины.
mikron
Дата: 10.07.2017 18:43:59
Реалная задача не из биоинформатики. Но вектор поиска верный и привел пока сюда.
mikron
Дата: 13.07.2017 11:58:29
Продолжая тему,
написал вот такой метод.

+

public class OnlineTestLCS {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			int r;

			r = FindLCS("ababcababababcabcab", "abcabcabc", 4);
			System.out.printf("LCS %s\n", r);

			r = FindLCS("abababababababab", "ababcabc", 2);
			System.out.printf("LCS %s\n", r);

			r = FindLCS("abababababababab", "abcabccabc", 2);
			System.out.printf("LCS %s\n", r);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

    static int FindLCS(String strA, String strB, int minLength)
    {
        if (strA.length() < strB.length())
            return FindLCS(strB, strA, minLength);

        if (strB.length() == 0)
        	return 0;


        minLength = Math.max(1, minLength);
        int r = 1 + minLength;
    	int[][] ML = new int[r][];
    	for(int i = 0; i < r; i++)
    		ML[i] = new int[strB.length()];

        int length = 0;
    	int[] SL = new int[strB.length()];

    	int m;
        for (int i = 0; i < strA.length(); ++i)
        {
        	// First fill current sequence length
            char chr = strA.charAt(i);
            for (int j = strB.length(); --j > 0;)
            {
                SL[j] = (chr == strB.charAt(j) ? 1 + SL[j - 1] : 0);
            }
            SL[0] = (chr == strB.charAt(0) ? 1 : 0);

            //Update matches
            ML[i % r][minLength - 1] = m = (SL[minLength - 1] == minLength ? minLength : ML[(i + minLength) % r][minLength - 1]);
        	if(length < m)
        	{
        		length = m;
        		if(m == strB.length())
        			return length;
        	}

            for (int j = minLength; j < strB.length(); ++j)
            {
        		// i + minLength == i - 1 : mod r
        		// i - minLength == i + 1 : mod r
            	if(SL[j] == minLength)
            	{
            		m = minLength + ML[(i + 1) % r][j - minLength];
            	}
            	else if(SL[j] > minLength)
            	{
            		m = Math.max(1 + ML[(i - 1) % r][j - 1], minLength + ML[(i + 1) % r][j - minLength]);
            	}
            	else
            	{
            		m = Math.max(ML[(i + minLength) % r][j], ML[i % r][j - 1]);
            	}
            	ML[i % r][j] = m;
            	if(length < m)
            	{
            		length = m;
            		if(m == strB.length())
            			return length;
            	}
            }
        }
        return length;
    }

}



Работает но медленно. Сложность O(n*m) где n и m размерности строк.

Собственно зачем мне нужна эта функция.
У меня есть К шаблонов и мне необходимо для одной строки найти наиболее подходящий из них.
Как критерий подходящего выбирается шаблон с максималной длинной общей последователности.
Строка берётся из файла и всё это в цикле.
получается для каждой строки и для каждого шаблона необчодимо вычислять длинну максималной обшей последователности.
Уже при 60 шаблонах обработка 80 Килобайтного файла занимает ... а у меня бсего 600 МБ этих файлов.

Какие будут мысли у сообшества по оптимизации алгоритма?