Самая длинная общая подстрока, ограниченная шаблоном - PullRequest
1 голос
/ 13 ноября 2011

Проблема:

У меня есть 3 строки s1, s2, s3.Каждый содержит мусорный текст с обеих сторон, с определяющим шаблоном в центре: text1+number1.number1 увеличивается на 2 в каждой строке.Я хочу извлечь text1+number1.

Я уже написал код для поиска number1

Как мне расширить функцию LCS для получения text1?

#include <iostream>

const std::string longestCommonSubstring(int, std::string const& s1, std::string const& s2, std::string const& s3);

int main(void) {
    std::string s1="hello 5", s2="bolo 7", s3="lo 9sdf";
    std::cout << "Trying to get \"lo 5\", actual result: \"" << longestCommonSubstring(5, s1, s2, s3) << '\"';
}

const std::string longestCommonSubstring(int must_include, std::string const& s1, std::string const& s2, std::string const& s3) {
    std::string longest;

    for(size_t start=0, length=1; start + length <= s1.size();) {
        std::string tmp = s1.substr(start, length);
        if (std::string::npos != s2.find(tmp) && std::string::npos != s3.find(tmp)) {
            tmp.swap(longest);
            ++length;
        } else ++start;
    }

    return longest;
}

Пример:

С "hello 5", "bolo 7", "lo 9sdf" Я хотел бы получить "lo 5"

Код:

Мне удалось написать простую функцию LCS ( контрольный пример ), но у меня возникли проблемы при написании этой модифицированной.

Ответы [ 4 ]

1 голос
/ 14 ноября 2011

Допустим, вы ищете шаблон * n, * n + 2, * n + 4 и т. Д. И у вас есть следующие строки: s1 = "привет 1, пока 2, ciao 1", s2 = "привет 3, пока 4, чао 2 "и s3 =" привет 5, пока 6, чао 5 ".Затем будет выполнено следующее:

//find all pattern sequences
N1 = findAllPatterns(s1, number);
 for i = 2 to n:
  for item in Ni-1:
   for match in findAllPatterns(si, nextPattern(item))
    Ni.add([item, (match, indexOf(match))]);

//for all pattern sequences identify the max common substring
maxCommonLength = 0; 
for sequence in Nn:
 temp = findLCS(sequence);
 if(length(temp[0]) > maxCommonLength):
  maxCommonLength = length(temp[0]);
  result = temp;

return result;

`Первая часть алгоритма идентифицирует последовательности: [(1, 6), (3, 6), (5, 6)], [(1, 19), (3, 6), (5, 6)], [(2, 12), (4, 12), (6, 12)]

Вторая часть будет указывать: ["hello 1 "," hello 3 "," hello 5 "] как самые длинные подстроки, соответствующие шаблону.

Алгоритм может быть дополнительно оптимизирован путем объединения двух частей и отбрасывания ранних последовательностей, которые соответствуют шаблону, но являются неоптимальными, но я предпочел представить его в двух частях для большей ясности.

- Редактировать фиксированный блок кода

0 голосов
/ 14 ноября 2011

Написал собственное решение:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

typedef std::pair<std::pair<std::string, std::string>, std::pair<std::pair<std::string, std::string>, std::pair<std::string, std::string>>> pairStringTrio;
typedef std::pair<std::string,std::pair<std::string,std::string>> stringPairString;

stringPairString longestCommonSubstring(const pairStringTrio&);
std::string strFindReplace(const std::string&, const std::string&, const std::string&);

int main(void) {
        std::string s1= "6 HUMAN ACTIONb", s2="8 HUMAN ACTIONd", s3="10 HUMAN ACTIONf";
        pairStringTrio result = std::make_pair(std::make_pair(s1, "6"), std::make_pair(std::make_pair(s2, "8"), std::make_pair(s3, "10")));

        stringPairString answer = longestCommonSubstring(result);
        std::cout << '\"' << answer.first << "\"\t\"" << answer.second.first << "\"\t\"" << answer.second.second << '\"';
}


stringPairString longestCommonSubstring(const pairStringTrio &foo) {
        std::string longest;

        for(size_t start=0, length=foo.first.first.size()-1; start + length <= foo.first.first.size();) {
                std::string s1_tmp = foo.first.first.substr(start, length);
                std::string s2_tmp = strFindReplace(s1_tmp, foo.first.second, foo.second.first.second);
                std::string s3_tmp = strFindReplace(s1_tmp, foo.first.second, foo.second.second.second);

                if (std::string::npos != foo.second.first.first.find(s2_tmp) && std::string::npos != foo.second.second.first.find(s3_tmp)) {
                        s1_tmp.swap(longest);
                        ++length;
                } else ++start;
        }

        return std::make_pair(longest, std::make_pair(strFindReplace(longest, foo.first.second, foo.second.first.second), strFindReplace(longest, foo.first.second, foo.second.second.second)));
}

std::string strFindReplace(const std::string &original, const std::string& src, const std::string& dest) {
        std::string answer=original;
        for(std::size_t pos = 0; (pos = answer.find(src, pos)) != answer.npos;)
                answer.replace(pos, src.size(), dest);
        return answer;
}
0 голосов
/ 13 ноября 2011

Вместо того, чтобы пытаться изменить внутреннее устройство алгоритма LCS, вы можете взять его вывод и найти его в s1. Оттуда ваш номер будет расположен по смещению длины выхода плюс 1.

0 голосов
/ 13 ноября 2011

Если вы уже знаете number1 и знаете, что все эти числа появляются только один раз в соответствующих строках, тогда должно работать следующее:

Я назову ваши строки s[0], s[1]и т. д. Установите longest = INT_MAX.Для каждой строки s[i] (i> = 0) просто:

  • Найдите, где number1 + 2 * i встречается в s[i].Предположим, что это происходит в позиции j.
  • If (i == 0) j0 = j;иначе
    • для (k = 1; k <= j && k <= самый длинный && s [i] [j - k] == s [0] [j0 - k]; ++ k) {}</li>
    • longest = k;

В конце longest будет длиной самой длинной подстроки, общей для всех строк.

По сути, мы просто сканируем в обратном направлении от точки, где мы находим число, ищем несоответствие с соответствующим символом в вашем s1 (моем s[0]) и отслеживаем, какая самая длинная совпадающая подстрока покав longest - это может оставаться неизменным или уменьшаться с каждой новой строкой, на которую мы смотрим.

...