Учитывая две последовательности, найдите самую длинную общую сумку символов - PullRequest
13 голосов
/ 21 августа 2010

Этот вопрос немного отличается от типа поиска самой длинной последовательности или подстроки из двух строк.

Если даны две строки одинакового размера N, найдите самые длинные подстроки из каждой строки, так что подстроки содержат одинаковыеbag of chars.

Две подстроки не обязательно должны иметь одинаковую последовательность.Но они должны иметь одинаковую сумку символов.

Например,

a = ABCDDEGF b = FPCDBDAX

Самая длинная подходящая сумка с символами - ABCDD (ABCDD от a,CDBDA от б)

Как решить эту проблему?


ОБНОВЛЕНИЕ

Цель состоит в том, чтобы найти подстроки из каждой входной строки, напримерчто у них та же сумка с символами.Говоря «подстрока», они должны быть последовательными символами.


Обновление : Изначально я думал о подходе динамического программирования.Это работает, как показано ниже.

Чтобы сравнить два пакета символов одинаковой длины K, потребуется O (K) время для достижения этого.Преобразуйте каждую строку в сокращенную форму:

ABCDDEGF -> A1B1C1D2E1G1F1
FPCDBDAX -> A1B1C1D2F1P1X1

Сокращенная форма представляет собой отсортированные алфавиты, за которыми следует число частот в строке.Построение, сортировка и сравнение сокращенных форм заняли бы всего O (K) времени.(Реализация может быть достигнута с использованием массива символов)

Два пакета символов равны, если их укороченные формы имеют одинаковые символы и соответствующие частоты.

Кроме того, требуется O (logK) время, чтобы найти разницу символов между двумя строками.

Теперь для двух входных строк:

  1. Если их укороченные формы идентичны, то это самая длинная общая сумкаchars.
  2. Найдите символы в строке1 так, чтобы они не появлялись в строке2.Токенизируйте string1 в несколько подстрок на основе этих символов.
  3. Найти символы в строке2, чтобы они не появлялись в строке1.Токенизируйте string2 в несколько подстрок на основе этих символов.
  4. Теперь у нас есть два списка строк.Сравните каждую пару (что, в свою очередь, является той же проблемой с меньшим размером ввода) и найдите самую длинную общую сумку символов.

Наихудшим случаем будет O (N 3 * 1049)*), и лучшим вариантом будет O (N).Есть идея получше?

Ответы [ 4 ]

5 голосов
/ 21 августа 2010

Создайте набор символов, присутствующих в a, и другой из символов, присутствующих в b.Пройдите через каждую строку и зачеркните (например, замените каким-либо другим невозможным значением) все символы, не входящие в набор, из другой строки.Найдите самую длинную строку, оставшуюся в каждом (т. Е. Самую длинную строку, состоящую только из «непробиваемых» символов).

Редактирование: Вот решение, которое работает примерно так, как отмечено выше, но в довольно специфичной для языка манере (используя языковые настройки C ++/ facets):

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

struct filter : std::ctype<char> {
    filter(std::string const &a) : std::ctype<char>(table, false) {
        std::fill_n(table, std::ctype<char>::table_size, std::ctype_base::space);

        for (size_t i=0; i<a.size(); i++) 
            table[(unsigned char)a[i]] = std::ctype_base::upper;
    }
private:
    std::ctype_base::mask table[std::ctype<char>::table_size];
};

std::string get_longest(std::string const &input, std::string const &f) { 
    std::istringstream in(input);
    filter *filt = new filter(f);

    in.imbue(std::locale(std::locale(), filt));

    std::string temp, longest;

    while (in >> temp)
        if (temp.size() > longest.size())
            longest = temp;
    delete filt;
    return longest;
}

int main() { 
    std::string a = "ABCDDEGF",  b = "FPCDBDAX";
    std::cout << "A longest: " << get_longest(a, b) << "\n";
    std::cout << "B longest: " << get_longest(b, a) << "\n";
    return 0;
}

Edit2: я полагаю, что эта реализация O (N) во всех случаях (один обход каждой строки).Это основано на std::ctype<char> использовании таблицы для поиска, которая равна O (1).С хэш-таблицей поиск также будет иметь O (1) ожидаемую сложность, но O (N) наихудший случай, поэтому общая сложность будет O (N) ожидаемой, но O (N 2 ) наихудший случай.С набором, основанным на сбалансированном дереве, вы получите O (N lg N) в целом.

3 голосов
/ 21 августа 2010

Просто примечание, чтобы сказать, что эта проблема не допустит «жадного» решения, в котором последовательно создаются большие пакеты путем расширения существующих выполнимых пакетов по одному элементу за раз.Причина в том, что даже если существует допустимая сумка длины k, не должно быть никакой подходящей сумки длины (k-1), как показывает следующий контрпример:

ABCD
CDAB

Очевидно, что есть длина4 сумки (A:1, B:1, C:1, D:1), разделяемые двумя нитями, но общей длины 3 сумки не существует.Это говорит о том, что проблема может быть довольно сложной.

1 голос
/ 22 августа 2010

давайте посмотрим на эту проблему следующим образом ... это решение будет более оптимизированным и будет очень легко кодировать, но прочитав def, и вы ДОЛЖНЫ прочитать код , чтобы понять ...иначе это будет звучать просто сумасшедшим и сложным

ДУМАЙТЕ ОБ ЭТОМ

в ваших вопросах 2 приведенные вами примерные строки позволяют принять их как два набора, то есть {x, y, z}, из символов ...

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

выше - это несколько свойств результата, но они будут работать только при использовании черезследующий алгоритм \ methodolgy

у нас есть два набора

a = {BAHYJIKLO}

b = {YTSHYJLOP}

Take

a U b = {-, -, H, Y, J, -, -, L, O}

b U a = {Y, -, -, H,Y, J, L, O, -}

это просто то, что я заменил символов, которые не подходили для объединения на "-"или любой специальный \ игнорируемый символ

, поэтому у нас есть две строки, из которых мы можем легко извлечь HYJ, LO, Y, HYJLO

теперь сравнение строк / подстрок и различная обработка требуют времени, поэтому я записываю эти строки \ подстроки в текстовый файл с разделением пробелом или разными строками ... чтобы при чтении файла я получал всю строку вместовложенный цикл для поиска подстроки или управления временными переменными ....

после того, как у вас есть HYJ, LO, Y, HYJLO я не думаю, что найти нужную вам проблемурезультат ....

ПРИМЕЧАНИЕ: если вы начнете обрабатывать строки и подстроки с помощью временных переменных и вложенных циклов, сначала создайте подстроку, затем найдите ее ... затемэто будет очень дорогостоящее решение ... вы должны использовать такую ​​подачу ...

char a[20], b[20]; //a[20] & b[30] are two strings
cin>>a; cin>>b;
int t=0;

open a temporary text file "file1" to write '(built-in-function works here)'
//a U b
for(int x=0; x<length(a); x++)
{
    t=0;

    for(int y=0; y<length(b); x++)
       { if( a[x] == b[y]) t=1; }

    if(t == 1)
       { 
          write 'a[x]' to the file1 '(built-in-function works here)'
          t=0;
       }
    else
       write a 'space' to the file1 '(built-in-function works here)'
}

//b U a
for(int x=0; x<length(a); x++)
{
    t=0;

    for(int y=0; y<length(b); x++)
       { if( b[x] == a[y]) t=1; }

    if(t == 1)
       {
         write 'a[x]' to the file1 '(built-in-function works here)'
         t=0;
       }
    else
       write a 'space' to the file1 '(built-in-function works here)'
}
/*output in the file wil be like this
_____FILE1.txt_____
  HYJ  LO Y HYJLO        
*/
//load all words in an array of stings from file '(built-in-function works here)'

char *words[]={"HYJ","LO","Y","HYJLO"};
int size=0,index=0;

for( int x=0; x<length(words); x++)
    for( int y=0; x<length(words); y++)
    {
       if( x!=y && words[x] is a substring of words[y] ) // '(built-in-function works here)'
          {
               if( length(words[x] ) < size )
               {
                     size = length(words[x];
                     index = x;
               }
          }
    }

 cout<< words[x]; 
 //its the desired result.. its pretty old school bu i think you get the idea

}

я написал код для ... он работает, если вы хотите, дай мне письмо, я отправлю его вам ... кстати, мне нравится эта проблема, и сложность этого алгоритма составляет 3n (квадрат)

0 голосов
/ 21 августа 2010

Вот моя довольно анти-pythonic реализация, которая тем не менее использует замечательные встроенные наборы и строки python.

a = 'ABCDDEGF'
b = 'FPCDBDAX'

best_solution = None
best_solution_total_length = 0

def try_expand(a, b, a_loc, b_loc):
    # out of range checks
    if a_loc[0] < 0 or b_loc[0] < 0:
        return
    if a_loc[1] == len(a) or b_loc[1] == len(b):
        return


    if set(a[a_loc[0] : a_loc[1]]) == set(b[b_loc[0] : b_loc[1]]):
        global best_solution_total_length, best_solution
        #is this solution better than anything before it?
        if (len(a[a_loc[0] : a_loc[1]]) + len(b[b_loc[0] : b_loc[1]])) > best_solution_total_length:
            best_solution = (a_loc, b_loc)
            best_solution_total_length = len(a[a_loc[0] : a_loc[1]]) + len(b[b_loc[0] : b_loc[1]])


    try_expand(a, b, (a_loc[0]-1, a_loc[1]), (b_loc[0], b_loc[1]))
    try_expand(a, b, (a_loc[0], a_loc[1]+1), (b_loc[0], b_loc[1]))
    try_expand(a, b, (a_loc[0], a_loc[1]), (b_loc[0]-1, b_loc[1]))
    try_expand(a, b, (a_loc[0], a_loc[1]), (b_loc[0], b_loc[1]+1))


for a_i in range(len(a)):
    for b_i in range(len(b)):
        # starts of the recursive expansion from identical letters in two substrings
        if a[a_i] == b[b_i]:
            # if substrings were expanded from this range before then there won't be an answer there
            if best_solution == None or best_solution[0][0] > a_i or best_solution[0][1] <= a_i or best_solution[1][0] > b_i or best_solution[1][1] <= b_i:
                    try_expand(a, b, (a_i, a_i), (b_i, b_i))


print a[best_solution[0][0] : best_solution[0][1]], b[best_solution[1][0] : best_solution[1][1]]

Забыл упомянуть, что это, очевидно, довольно грубый подход, и я уверен, что есть алгоритмработает намного, намного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...