Самая длинная палиндромная подстрока рекурсивный подход сверху вниз - PullRequest
0 голосов
/ 09 декабря 2018

Я пытаюсь решить Самая длинная палиндромная подстрока в Leetcode.Мне известны решения этой проблемы, такие как расширение вокруг центра или динамическое программирование снизу вверх .В чисто образовательных целях я хотел решить эту проблему рекурсивным способом.Я пытаюсь найти решение, подобное тому, что описано здесь или здесь .(проблема немного в другом).У меня есть эта функция:

private (int Start, int End) Longest(string s, int i, int j)

, которая принимает строку + начальную и конечную позицию поиска.Возвращение кортежа - начало и конец самого длинного палиндрома.Я пытаюсь разделить на следующие случаи:

  1. , если s [i] == s [j] исследовать Дольше всего (s, i + 1, j-1)
  2. Исследовать дольше(s, i + 1, j)
  3. Исследовать самое длинное (s, i, j - 1)
  4. Возвращать самое длинное (максимальное различие между возвращенным началом и концом) из этих трех

Конечно, я использую словарь с кортежем (int, int) в качестве ключа (значения i и j), чтобы запомнить все вычисленные результаты, чтобы не вычислять их снова.

Полный код приведен ниже, но оночень грязно после нескольких итераций, когда я пытался исправить алгоритм.Я полагаю, что конкретный код не очень важен.

Код, похоже, возвращает правильные результаты, но в Leetcode превышен лимит времени.Есть ли правильное быстрое рекурсивное решение?Я полагаю, что должно быть так, как существует DP восходящее решение.

код:

private readonly IDictionary<(int, int), (int, int)> _mem = new Dictionary<(int, int), (int, int)>();

private (int Start, int End) Longest(string s, int i, int j) {
    if (i >= j) {
        return (i, j);
    }

    if (_mem.TryGetValue((i, j), out var ret)) {
        return ret;
    }

    var newI = i + 1;
    var newJ = j - 1;

    ValueTuple<int, int> removingTwo;

    if (s[i] == s[j])
    {
        removingTwo = Longest(s, newI, newJ);

        if (removingTwo.Item1 == newI && removingTwo.Item2 == newJ) {
            removingTwo.Item1--;
            removingTwo.Item2++;
        }
    }
    else {
        removingTwo = (1, 0);
    }

    var removingFirst = Longest(s, newI, j);
    var removingLast = Longest(s, i, newJ);  

    var mT = removingTwo.Item2 - removingTwo.Item1;
    var mF = removingFirst.End - removingFirst.Start;
    var mL = removingLast.End - removingLast.Start;

    var max = Math.Max(mT, mF);
    max = Math.Max(max, mL);

    ValueTuple<int, int> retVal;

    if (max == mT) retVal = removingTwo;
    else if (max == mF) retVal = removingFirst;
    else retVal = removingLast;

    _mem.Add((i, j), retVal);

    return retVal;

}

Редактировать : рабочее восходящее решение (скопировано из geegsforgeegs ):

public string LongestPalindrome(string s) {
    if (s.Length == 0) return "";
    var table = new bool[s.Length, s.Length];
    var len = s.Length;
    for (int i = 0; i < len; i++) {
        table[i,i] = true;
    }

    var start = 0;
    var max = 1;
    for (int i = 0; i < len - 1; i++) {
        if (s[i] == s[i + 1]) {
            start = i;
            max = 2;
            table[i, i+1] = true;
        }
    }

    for (int k = 3; k <= len; ++k) { 

              // Fix the starting index 
        for (int i = 0; i < len - k + 1; ++i)  
        { 
            // Get the ending index of substring from 
            // starting index i and length k 
            int j = i + k - 1; 

            // checking for sub-string from ith index to 
            // jth index iff str.charAt(i+1) to  
            // str.charAt(j-1) is a palindrome 
            if (table[i + 1, j - 1] && s[i] == s[j]) { 
                table[i,j] = true; 

                if (k > max) { 
                    start = i; 
                    max = k; 
                } 
            } 
        } 
    } 

    return s.Substring(start, max);
}

1 Ответ

0 голосов
/ 10 декабря 2018

Вот рекурсивный метод в Python, который проходит тест LeetCode.Возможно, они ищут решение с постоянным пространством.

f(i, k) возвращает (l, j), самый большой кортеж длины l и его начальный индекс j.max в этом случае смотрит на первый элемент возвращенного кортежа, который l, длина палиндрома.

def longestPalindrome(self, s):
  def f(i, k):
    return max(
      # next iteration
      f(i - 1, 1) if k < 2 and i > 0 else (-1,-1),
      f(i - 1, 2) if k < 2 and i > 0 and s[i-1] == s[i] else (-1, -1),

      # a larger palindrome than this one
      f(i - 1, k + 2) if i > 0 and i + k < len(s) and s[i-1] == s[i + k] else (-1, -1),

      # this one
      (k, i)
    )

  (l, j) = f(len(s) - 1, 1)
  return s[j:j+l]
...