Удаление минимальных букв из строки "A" для удаления всех экземпляров строки "B" - программирование
Подтвердить что ты не робот

Удаление минимальных букв из строки "A" для удаления всех экземпляров строки "B"

Если у нас есть строка A длины N и строка B длины M, где M < N, могу ли я быстро вычислить минимальное количество букв, которые мне нужно удалить из строки A, чтобы строка B не встречалась как подстрока в A?

Если у нас крошечная длина строки, эта проблема довольно проста для грубой силы: вы просто перебираете битовую маску от 0 до 2^N и видите, если B встречается как подстрока в этой подпоследовательности A. Однако, когда N может достигать 10 000, а M может достигать 1000, этот алгоритм, очевидно, быстро разваливается. Есть ли более быстрый способ сделать это?

Пример: A = ababaa B = aba. Ответ = 1. При повторном выполнении второго A в будет abbaa, который не содержит B.

Изменить: Пользователь n.m. размещен отличный пример счетчика: aabcc и abc. Мы хотим удалить одиночный B, потому что удаление любых A или c создаст другой экземпляр строки abc.

4b9b3361

Ответ 1

Решите его с помощью динамического программирования. Пусть dp [i] [j] минимальный оператор, чтобы A [0... i-1] имел суффикс B [0... j-1], а также A [0... i] t содержать B, dp[i][j] = Infinite для индексации оператора невозможно. Тогда

if(A[i-1]=B[i-1]) 
   dp[i][j] = min(dp[i-1][j-1], dp[i-1][j])    
else dp[i][j]=dp[i-1][j]`,

return min(A[N][0],A[N][1],...,A[N][M-1]);`

Ответ 2

Можно ли выполнить поиск по графам строки A. Это, вероятно, слишком медленно для больших N и специальных входных данных, но оно должно работать лучше, чем экспоненциальный алгоритм грубой силы. Возможно, BFS.

Ответ 3

Я не уверен, что этот вопрос по-прежнему вызывает интерес, но у меня есть идея, что, возможно, это сработает.

Как только мы решили, что проблема заключается не в том, чтобы найти подстроку, нужно решить, какую букву удобнее удалить из строки A, решение для меня выглядит довольно простым: если вы найдете вхождение строки B в A, самое лучшее, что вы можете сделать, это просто удалить char, который находится внутри строки, закрыт для правильного брандмауэра... скажем, предыдущий. Поэтому, если у вас есть подстрока, которая на самом деле заканчивается, как она начинается, если вы сначала удаляете char, вы просто удаляете одно из B-событий, в то время как вы можете фактически удалить два раза.

Алгоритм в псевдокозе:

String A, B;
int occ_posit = 0;
N = B.length();

occ_posit = A.getOccurrencePosition(B); // pseudo function that get the first occurence of B into A and returns the offset (1° byte = 1), or 0 if no occurence present.

while (occ_posit > 0)  // while there are B into A
{
    if (B.firstchar == B.lastchar)  // if B starts as it ends
    {
        if (A.charat[occ_posit] == A.charat[occ_posit+1])
            A.remove[occ_posit - 1]; // no reason to remove A[occ_posit] here
        else
            A.remove[occ_posit]; // here we remove the last char, so we could remove 2 occurencies at the same time
    }
    else
    {
        int x = occ_posit + N - 1;
        while (A.charat[x + 1] == A.charat[x])
            x--; // find the first char different from the last one

        A.remove[x]; // B does not ends as it starts, so if there are  overlapping instances they overlap by more than one char. Removing the first that is not equal to the char following B instance, we kill both occurrencies at once.
    }
}

Объясним пример:

A = "123456789000987654321" B = "890"

прочитайте это как таблицу:

occ_posit:  123456789012345678901

       A = "123456789000987654321"
       B =        "890"

первое вхождение - в occ_posit = 8. B не заканчивается по мере его запуска, поэтому он попадает во второй цикл:

int x = 8 + 3 - 1 = 10;
while (A.charat[x + 1] == A.charat[x])
    x--; // find the first char different from the last one
A.remove[x];

находим, что A.charat11 соответствует A.charat [10] (= "0" ), поэтому x становится 9, а затем при выходе, поскольку A.charat [10] не соответствует A.charat9. A затем ставьте:

A = "12345678000987654321"

в котором больше нет случаев.

Попробуйте с другим: A = "abcccccccccc" B = "abc"

первое вхождение находится в occ_posit = 1. B не заканчивается по мере его запуска, поэтому он попадает во второй цикл:

int x = 1 + 3 - 1 = 3;
while (A.charat[x + 1] == A.charat[x])
    x--; // find the first char different from the last one
A.remove[x];

находим, что A.charat4 соответствует A.charat [3] (= "c" ), поэтому x становится 2, а затем при выходе, поскольку A.charat [3] не соответствует A.charat2. A затем ставьте:

A = "accccccccc"

попробуйте с перекрытием:

A = "abcdabcdabff" B = "abcdab"

алгоритм приводит к: A = "abcdacdabff", который не имеет больше случаев.

наконец, одно перекрытие буквы:

A = "abbabbabbabba" B = "abba"

B заканчивается, когда он начинается, поэтому он вводит первый, если:

if (A.charat[occ_posit] == A.charat[occ_posit+1])
            A.remove[occ_posit - 1]; // no reason to remove A[occ_posit] here
        else
            A.remove[occ_posit]; // here we remove the last char, so we could remove 2 occurencies at the same time

который позволяет удалить последний экземпляр "a" экземпляра B. Итак:

1 ° шаг: A = "abbbbabbabba" Шаг 2 °: A = "abbbbabbbba", и мы закончили.

Надеюсь, что это поможет

EDIT: обратите внимание, что algotirhm необходимо скорректировать немного, чтобы не дать ошибку, когда вы находитесь ближе к концу A с вашим поиском, но это просто проблема программирования.

Ответ 4

Вот эскиз, который я придумал.

Во-первых, если A содержит любые символы, которые не найдены в B, разделите A на кучу меньших строк, содержащих только те символы, которые находятся в B. Применяйте алгоритм на каждой из меньших строк, затем склеивайте их вместе получить общий результат. Это действительно работает как оптимизация.

Далее, проверьте, содержит ли А какое-либо из B. Если этого не происходит, все готово. Если A = B, то удалите все из них.

Я думаю, что может работать относительно жадный алгоритм.

Сначала отметьте все символы в A, которые принадлежат хотя бы одному вхождению B. Пусть A = aabcbccabcaa, B = abc. Bolding указывает эти отмеченные символы:

a abc bcc abc aa. Если есть перекрытие, отметьте все возможное. Эта операция наивно приблизительно (A-B) операций, но я считаю, что это может быть сделано вокруг (A/B) операций.

Рассмотрим удаление каждой отмеченной буквы в A: a abc bcc abc aa.

Проверьте, удаляет ли отмеченное письмо количество отмеченных букв. Вам нужно только проверить подстроки, на которые может повлиять удаление буквы. Если B имеет длину 4, нужно будет удалить только подстроки, начинающиеся в следующих местах, если x проверяется:

-------x------
    ^^^^

Любые дальнейшие левые или правые будут существовать независимо от наличия x.

Например:

Маркировка [a] в следующей строке: a [a] bc bcc abc aa.

Его удаление дает abcbccabcaa, который при маркировке создает abc bcc abc aa, который имеет равное количество помеченных символов. Поскольку для этой операции требуется только относительное число, это может быть сделано примерно в 2 раза для каждой выбранной буквы. Для каждого назначьте относительную разницу между ними. Выберите произвольный, максимальный, и удалите его. Повторяйте до конца. Каждый проход составляет примерно до 2AB операций, для максимума A проходит, давая общее время около 2A ^ 2 B.

В приведенном выше примере эти значения присваиваются:

aabcbccabcaa
 033   333

Таким образом, произвольное удаление первого отмеченного b дает вам: aacbccabcaa. Если вы повторите этот процесс, вы получите:

aacbccabcaa
      333  

Окончательный результат выполнен.

Я считаю, что алгоритм правильно минимален. Я думаю, что верно, что всякий раз, когда А требует только одного удаления, алгоритм должен быть оптимальным. В этом случае письмо, которое уменьшает максимально возможные совпадения (т.е. Все из них), должно быть лучше. Однако я не могу придумать такого доказательства. Мне было бы интересно найти любые встречные примеры для оптимальности.

Ответ 5

Найдите в каждой строке подстроки каждой подстроки.

Затем, используя алгоритм динамического программирования (так memoize промежуточные значения), удалите каждую букву, которая является частью подстроки из основной строки, добавьте 1 к счету и повторите.

Вы можете найти буквы, потому что они находятся внутри индексов каждого индекса соответствия + длины B.

A = ababaa
B = aba
count = 0

indeces = (0, 2)

A = babaa, aabaa, abbaa, abbaa, abaaa, ababa
B = aba
count = 1

(2nd abbaa is memoized)

indeces = (1), (1), (), (), (0), (0, 2)

answer = 1

Вы можете сделать еще один шаг и попытаться сохранить подменю подстроки подстроки подстрок, но на самом деле это может быть не прирост производительности.

Не уверен в точном ограничении, но не должен занимать слишком много времени.

Ответ 6

Хорошо, я думаю, что у меня есть простое решение.
Я буду притворяться, что A, B - только строки двоичных чисел.

A= 011010101001001101
B= 010

Применить фильтр XNOR на A, с B. Результат будет C.
Предположим, что начало B находится в его центре. (Это означает, что вы ищете B в A. Если вы найдете совпадение, поместите 1 в C в это место.)

A= 011010101001001101
C= 000010101001000000

Просто, C показывает места, где A содержит B.
Вы могли бы удалить все символы в местах, показанных C, например, и это решит вашу проблему. Но это не было бы оптимальным решением.

Но найти оптимальное решение легко.
Хорошо, теперь проблема намного проще. Я могу объяснить это как эти проблемы с алгоритмом:

  • C показывает местоположения картин. Каждый защитник может защитить диапазон X (X = длина (B)/2 + 1). Поместите минимальное количество охранников, чтобы все картины были защищены.
  • Удалить из C минимальное количество 1. Для каждого 1 удаляемого, все 1 в окрестности lenth (B)/2 + 1 также удаляются.

Это не новая проблема, и существуют существующие решения. Примените одно такое решение.
И это даст следующее. D показывает местоположения 1 удаленных:

C= 000010101001000000
D= 000000100001000000

Подсчитайте число 1 в D → 2. Это означает, что вы можете удалить 2 элемента из A, так что B не является подстрокой A.