ПРИМЕЧАНИЕ: Обычно я не пишу два ответа, и если вы чувствуете, что он липкий, не стесняйтесь комментировать этот и проголосовать за него.Этот ответ является более оптимизированным решением, но я хотел дать самый простой, о котором я мог бы думать в первую очередь, а затем поставить это в другом ответе, чтобы не смутить этих двух. В основном они предназначены для разных аудиторий.
Ключом к эффективному решению этой проблемы является не отбрасывание информации о более коротких общих подстроках при поиске более длинных. Наивно, вы проверяете каждую подстроку на другую, но если вы знаете, что «AB» соответствует «ABC», а ваш следующий символ - C, не проверяйте, есть ли «ABC» в «ABC», просто проверьте что пятно после «AB» является «C».
Для каждого символа в A вам необходимо проверить все буквы в B, но поскольку мы перестаем просматривать B, как только более длинная подстрока больше не возможна, это значительно ограничивает количество проверок. Каждый раз, когда вы получаете более длинный матч вперед, вы исключаете проверки на внутреннем сервере, потому что он больше не будет более длинной подстрокой.
Например, если A и B являются длинными, но не содержат общих букв, каждая буква в A будет сравниваться с каждой буквой в B для времени выполнения A * B.
Для последовательности, в которой имеется много совпадений, но длина совпадения не является большой частью длины более короткой строки, у вас есть комбинации A * B для проверки на более короткую из двух строк (A или B), приводящий к A * B * A или A * B * B, что в основном O (n^3) для аналогичных строк длины. Я действительно думал, что оптимизация в этом решении будет лучше, чем n^3, хотя есть трижды вложенные для циклов, но, похоже, это не так хорошо, как я могу сказать.
Я думаю об этом еще немного. Либо найденные подстроки НЕ являются значительной частью длины строк, и в этом случае оптимизации не очень много, но сравнения для каждой комбинации A * B не масштабируются с помощью A или B и выпадают на константы - OR - они являются значительной долей A и B и непосредственно делятся на комбинации A * B, которые необходимо сравнивать.
Я как раз могу спросить это в вопросе.
int lcs(char * A, char * B)
{
int length_a = strlen(A);
int length_b = strlen(B);
// these hold the position in A of the longest common substring
int longest_length_found = 0;
// for each character in one string (doesn't matter which), look for incrementally larger strings in the other
for (int a_index = 0; a_index < length_a - longest_length_found; a_index++) {
for (int b_index = 0; b_index < length_b - longest_length_found; b_index++) {
// offset into each string until end of string or non-matching character is found
for (int offset = 0; A[a_index+offset] != '\0' && B[b_index+offset] != '\0' && A[a_index+offset] == B[b_index+offset]; offset++) {
longest_length_found = longest_length_found > offset ? longest_length_found : offset;
}
}
}
return longest_found_length;
}
Действительно не нравится, как вы выполняете 'Y = X;' - это утечка памяти и потенциал переполнения буфера. – paddy
Было бы разумно показать первую пару ошибок из 'valgrind'; нам не нужно было догадываться, что он сообщает. –
используйте имена реальных переменных. 'a_len' за' m', 'b_len' за n,' longestSoFar' за 'X' (если это так) и т. д. – djechlin