Java самый длинный палиндром не работает

Я работаю над программой, которая дает мне самый длинный палиндром:

Вот мой код, он отлично работает для самой длинной подпоследовательности. Но я хочу сделать это по-другому, например:

havanbava, я хочу результат как avanava, но моя программа дает мне ava. Как это исправить.

static void printSubStr(String str, int low, int high) {
    System.out.println(str.substring(low, high + 1));
}

static int longestPalindrome(String str) {
    int maxLength = 1; // The result (length of LPS)

    int start = 0;
    int len = str.length();

    int low, high;

    for (int i = 1; i < len; ++i) {
        low = i - 1;
        high = i;
        while (low >= 0 && high < len && str.charAt(low) == str.charAt(high)) {
            if (high - low + 1 > maxLength) {
                start = low;
                maxLength = high - low + 1;
            }
            --low;
            ++high;
        }

        low = i - 1;
        high = i + 1;
        while (low >= 0 && high < len && str.charAt(low) == str.charAt(high)) {
            if (high - low + 1 > maxLength) {
                start = low;
                maxLength = high - low + 1;
            }
            --low;
            ++high;
        }
    }

    System.out.print("Longest palindrome substring is: ");
    printSubStr(str, start, start + maxLength - 1);

    return maxLength;
}

«Хаванбава, я хочу результат в виде аванавы», куда делась буква «б»?

Andy Turner 23.08.2018 20:31
avanava не является подстрокой havanbava
ernest_k 23.08.2018 20:31

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

learner 23.08.2018 20:34

А) палиндромы определяются не так. Палиндром - «вперед - это то же самое, что и назад». Б) если вы действительно хотите, чтобы «XblaYblubZfooYbarX» приводил к XYZYX, вам нужно сделать гораздо больше. Потому что тогда мы говорим о том, чтобы пройти по всему дереву возможностей исключения любой конкретной подстроки. Затем вы говорите о дереве поиска огромный и стратегиях поиска DFS или BFS. Честно говоря, на вашем месте я бы остановился на точном определении палиндрома и не стал бы использовать ваш гораздо более сложный вариант.

GhostCat 23.08.2018 20:47

@AndyTurner Вопрос говорит о «самой длинной подпоследовательности», а не о «самой длинной подстроке», а avanavaявляется - это подпоследовательностьhavanbava.

Andreas 23.08.2018 21:01

@GhostCat На самом деле результат для XblaYblubZfooYbarX будет одним из [XbYblbYbX, XbYbubYbX, XaYblbYaX, XaYbubYaX]

Andreas 23.08.2018 23:30

Видите ли, это так легко ошибиться :-)

GhostCat 24.08.2018 06:09

@ user3181365, я обновил свой ответ более полным объяснением идеи с точки зрения динамического программирования. Надеюсь, это будет полезно.

dim 24.08.2018 15:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
8
136
2

Ответы 2

Учтите, что есть две разные самые длинные подпоследовательности палиндрома (аванава и Avabava), вы можете найти все подпоследовательности итеративно, а затем проверить, являются ли они палиндромом. Я использую карту для сохранения всех подпоследовательностей палиндрома и их длины, а затем просматриваю карту, чтобы выбрать самую длинную. Это решение занимает только первое самое длинное ((аванава):

import java.util.HashMap;
import java.util.Map;

public class Palindrome {
    // set to store all the subsequences
    static Map<String, Integer> subsequences = new HashMap<>();


    public static void main(String[] args) {
        subsequence("havanbava");

        //storing the higher key/value
        Map.Entry<String, Integer> maxEntry = null;

        for (Map.Entry<String, Integer> entry : subsequences.entrySet())
        {
            if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0)
            {
                maxEntry = entry;
            }
        }

        System.out.println(maxEntry.getKey());

    }

    static boolean isPalindrome(String str) {
         int n = str.length();
          for (int i = 0; i < (n/2); ++i) {
             if (str.charAt(i) != str.charAt(n - i - 1)) {
                 return false;
             }
          }

          return true;
    }


    static void subsequence(String str)
    {
        for (int i = 0; i < str.length(); i++) {


            for (int j = str.length(); j > i; j--) {
                String sub_str = str.substring(i, j);

                if (!subsequences.containsKey(sub_str)
                        && isPalindrome(sub_str))
                    subsequences.put(sub_str,sub_str.length());

                for (int k = 1; k < sub_str.length() - 1; k++) {
                    StringBuffer sb = new StringBuffer(sub_str);

                    sb.deleteCharAt(k);

                    subsequence(sb.toString());
                }
            }
        }
    }

}

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

Это возможное решение, если вы хотите, чтобы все были самыми длинными подпоследовательностями (одинаковой длины):

import java.util.HashMap;
import java.util.Map;

public class Palindrome {
    // set to store all the subsequences
    static Map<String, Integer> subsequences = new HashMap<>();


    public static void main(String[] args) {
        subsequence("havanbava");

        //storing the higher key/value
        Map<String, Integer> maxEntries = new HashMap<String, Integer>();

        for (Map.Entry<String, Integer> entry : subsequences.entrySet())
        {
            if (maxEntries.isEmpty()){
                maxEntries.put(entry.getKey(),entry.getValue());
            }else if (entry.getValue().compareTo( maxEntries.entrySet().iterator().next().getValue() ) == 0)
            {
                maxEntries.put(entry.getKey(),entry.getValue());
            }else if ( entry.getValue().compareTo(maxEntries.entrySet().iterator().next().getValue()) > 0){
                maxEntries.clear();
                maxEntries.put(entry.getKey(),entry.getValue());
            }
        }
        for (Map.Entry<String, Integer> maxEntry : maxEntries.entrySet())
            System.out.println(maxEntry.getKey());

    }

    static boolean isPalindrome(String str) {
         int n = str.length();
          for (int i = 0; i < (n/2); ++i) {
             if (str.charAt(i) != str.charAt(n - i - 1)) {
                 return false;
             }
          }

          return true;
    }


    static void subsequence(String str)
    {
        for (int i = 0; i < str.length(); i++) {


            for (int j = str.length(); j > i; j--) {
                String sub_str = str.substring(i, j);

                if (!subsequences.containsKey(sub_str)
                        && isPalindrome(sub_str))
                    subsequences.put(sub_str,sub_str.length());

                for (int k = 1; k < sub_str.length() - 1; k++) {
                    StringBuffer sb = new StringBuffer(sub_str);

                    sb.deleteCharAt(k);

                    subsequence(sb.toString());
                }
            }
        }
    }

}

Это типичная проблема динамическое программирование. Вы можете найти длину самая длинная подпоследовательность палиндрома (LPS) во времени O(n^2). Вы должны построить матрицу мемоизации следующим образом:

     0 1 2 3 4 5 6 7 8 -> indexes
     h a v a n b a v a -> input string
0 h  1 1 1 3 3 3 3 5 7 -> max_len = 7 -> a v a b a v a
1 a  0 1 1 3 3 3 3 5 7 
2 v  0 0 1 1 1 1 3 5 5 
3 a  0 0 0 1 1 1 3 3 3 
4 n  0 0 0 0 1 1 1 1 3 
5 b  0 0 0 0 0 1 1 1 3 
6 a  0 0 0 0 0 0 1 1 3 
7 v  0 0 0 0 0 0 0 1 1 
8 a  0 0 0 0 0 0 0 0 1 

Идея состоит в том, чтобы построить такую ​​матрицу, чтобы matrix[i][j] (0 <= i, j <= len) был равен LPS от i-го индекса до j-го индекса входа.

Если LPS между i-м и j-м индексом (i<=j) имеет длину LPS(i, j), то L:

  • Для L=1 имеем: LPS(0,0) = LPS(1,1) = ... = LPS(8,8) = 1
  • Для L=2: LPS(0,1) = LPS(1,2) = ... = LPS(7,8) = 1 (если input[i]=input[i+1], LPS(i,i+1)=2, то есть aa или bb, но у нас такого корпуса нет)
  • Для L=3 имеем:
    • LPS(0,2) = max(LPS(0,1), LPS(1,2)) = max(1, 1) = 1
    • LPS(1,3) = LPS(1,1) + 2 = 3
    • ...

Еще примеры:

LPS(0,4) = max(LPS(0,3), LPS(1,4))=max(3,2) = 3
LPS(2,7) = LPS(3,6) + 2 = 3 + 2 = 5

Итак, правило:

if input[i] != input[j]
    LPS(i,j) = max(LPS(i,j-1), LPS(i+1,j))
else
    LPS(i,j) = LPS(i+1,j-1) + 2

Вы можете найти блестящее объяснение LPS здесь. Этот парень очень хорошо объясняет, и я настоятельно рекомендую его плейлист для динамического программирования. Конечно, проблема может быть решена с помощью рекурсивного решения (как и любая проблема DP), но здесь я предлагаю пример решения DP:

public static String findLPS(String input) {
    int len = input.length();

    // initializes a diagonal matrix
    int[][] matrix = new int[len][len];
    for (int i = 0; i < matrix.length; i++) {
        matrix[i][i] = 1;
    }

    // finds the length of the longest palindrome subsequence
    for (int jj = 1; jj < len; jj++) {
        int i = 0;
        int j = jj;
        while (i < len && j < len) {
            if (input.charAt(i) == input.charAt(j)) {
                matrix[i][j] = matrix[i + 1][j - 1] + 2;
            } else {
                matrix[i][j] = Math.max(matrix[i + 1][j], matrix[i][j - 1]);
            }
            i++; j++;
        }
    }

    // reconstruct the solution from the matrix
    char[] path = new char[len];
    int i = 0;
    int j = len - 1;

    if (matrix[i][j] == 1) {
        return input.charAt(0) + "";
    }

    while (matrix[i][j] != 0) {
        if (matrix[i][j] == matrix[i + 1][j]) {
            i += 1;
        } else if (matrix[i][j] == matrix[i][j - 1]) {
            j -= 1;
        } else {
            path[i] = input.charAt(i);
            path[j] = input.charAt(j);
            i++; j--;
        }
    }

    String solution = "";
    for (int k = 0; k < len; k++) {
        if (path[k] != 0) {
            solution += path[k];
        }
    }

    return solution;
}

Другие вопросы по теме