Поиск минимальной строки, удовлетворяющей некоторым условиям

Недавно во время собеседования мне была задана следующая проблема.

Учитывая строку S, мне нужно найти другую строку S2, такую, что S2 является подпоследовательностью S, а также S является подпоследовательностью S2 + reverse (S2). Здесь '+' означает конкатенацию. Мне нужно вывести минимальную длину S2 для заданного S.

Мне сказали, что это проблема динамического программирования, но я не смог ее решить. Может ли кто-нибудь помочь мне с этой проблемой?

ИЗМЕНИТЬ -

Есть ли способ сделать это в O (N 2) или меньше.

Ответы

Ответ 1

В этой проблеме есть два важных аспекта.

  • Так как нам нужно S как подстроку S2 + reverse (S2), S2 должно иметь длина по крайней мере n/2.
  • После конкатенации S2 и обратного (S2) существует шаблон, где алфавиты повторяются, например

введите описание изображения здесь

Таким образом, решение состоит в проверке от центра S до конца S для любых последовательных элементов. Если вы найдете его, проверьте элементы с обеих сторон, как показано.

введите описание изображения здесь

Теперь, если вы можете достичь до конца строки, минимальное количество элементов (результат) - это расстояние от начала до точки, где вы находите последовательные элементы. В этом примере его C i.e 3.

Мы знаем, что это может случиться не всегда. т.е. вы не сможете найти последовательные элементы в центре. Скажем, последовательные элементы после центра, то мы можем сделать тот же тест.

Основная строка

введите описание изображения здесь

подстроку

введите описание изображения здесь

Конкатенированная строка

введите описание изображения здесь

Теперь возникает главное сомнение. Почему мы рассматриваем только левую сторону, начиная с центра? Ответ прост, конкатенированная строка выполняется с помощью S + reverse (S). Таким образом, мы уверены, что последний элемент в подстроке происходит последовательно в конкатенированной строке. Нет никакого способа, чтобы любое повторение в первой половине основной строки могло дать лучший результат, потому что по крайней мере мы должны иметь n алфавитов в конечной конкатенированной строке

Теперь вопрос сложности: Поиск последовательных алфавитов дает максимум O (n) Теперь проверка элементов с обеих сторон итеративно может дать худшую сложность O (n). максимальные n/2 сравнения. Мы можем терпеть неудачу много раз, выполняя вторую проверку, так что у нас есть мультипликативная связь между сложностями i.e O (n * n).

Я считаю, что это правильное решение и еще не нашло лазейки.

Ответ 2

Каждый символ из S может быть включен в S2 или нет. С этим мы можем построить рекурсию, которая пробует два случая:

  • первый символ S используется для обложки,
  • первый символ S не используется для покрытия,

и вычислить минимум этих двух покрытий. Чтобы реализовать это, достаточно проследить, сколько из S покрыто уже выбранным S2 + обратным (S2).

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

Простая реализация python:

cache = {}

def S2(S, to_cover):
    if not to_cover:  # Covered
        return ''
    if not S:         # Not covered
        return None
    if len(to_cover) > 2*len(S):  # Can't cover
        return None
    key = (S, to_cover)
    if key not in cache:
        without_char = S2(S[1:], to_cover)     # Calculate with first character skipped
        cache[key] = without_char
        _f = to_cover[0] == S[0]
        _l = to_cover[-1] == S[0]
        if _f or _l:
            # Calculate with first character used
            with_char = S2(S[1:], to_cover[int(_f):len(to_cover)-int(_l)])
            if with_char is not None:
                with_char = S[0] + with_char  # Append char to result
                if without_char is None or len(with_char) <= len(without_char):
                    cache[key] = with_char
    return cache[key]

s = '21211233123123213213131212122111312113221122132121221212321212112121321212121132'
c = S2(s, s)
print len(s), s
print len(c), c

Ответ 3

Скажем, что S2 - "яблоко" . Тогда мы можем сделать это предположение:

S2 + reverseS2 >= S >= S2
"appleelppa" >= S >= "яблоко"

Итак, данный S будет что-то, в том числе "яблоко" , не более, чем "appleelppe". Это может быть "appleel" или "appleelpp".

String S ="locomotiffitomoc";
// as you see S2 string is "locomotif" but 
// we don't know S2 yet, so it blank
String S2 = "";
for (int a=0; a<S.length(); a++) {
    try {
        int b = 0;
        while (S.charAt(a - b) == S.charAt(a + b + 1))
            b++;
        // if this for loop breaks that means that there is a character that doesn't match the rule
        // if for loop doesn't break but throws an exception we found it.
    } catch (Exception e) {
        // if StringOutOfBoundsException is thrown this means end of the string.
        // you can check this manually of course.
        S2 = S.substring(0,a+1);
        break;
    }
}
System.out.println(S2); // will print out "locomotif"

Поздравляем, вы нашли минимум S2.