Как использовать/модифицировать алгоритм Кнута-Морриса-Пратта для преобразования любой заданной строки в палиндром

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

Пример выполнения:

Input: 123333
Output: 12333321

Input: 789
Output: 78987

Input: 1221
Output: 1221221

**Обратите внимание, что палиндром НЕ должен возвращать один и тот же палиндром.

Я попытался использовать модифицированный алгоритм KMP, как указано здесь.

Я возвращаю строку и сравниваю ее с обратной + исходной строкой, а затем добавляю несоответствия к исходной строке.

Однако моя функция работает только для входных данных с конечными цифрами (первый пример ввода), однако ввод типа 1234 вернет 1234123, «92837465» вернет «928374659283746»

public static int[] computelps(String sample){
    int[] lps = new int[sample.length()];
    lps[0] = 0;
    int i = 1;
    int len = 0; // length of previous longest prefix suffix
    while (i < sample.length()) {
        if (sample.charAt(i) == sample.charAt(len)) {
            len++;
            lps[i] = len;
            i++;
        }
        else
        {
            if (len != 0) {
                len = lps[len - 1];
            }
            else {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

public static void Solution(File samplefile) throws Exception {
    BufferedReader br = new BufferedReader(new FileReader(samplefile));

    String firstline = br.readLine();
    String line;


    while ((line = br.readLine()) != null) {
        String reverse_str = "";
        String newline = line.replace(".", "");

        for (int i = newline.length() - 1; i >= 0; i--) {
            reverse_str += newline.charAt(i);
        }

        int [] lps = computelps(reverse_str); // computes the lps of the pattern string
        String tot = reverse_str + newline;

        // KMP Algorithm modified.

        int x = 0; // index for total_string(tot)
        int y = 0; // index for pattern
        String palindrome = newline;

        while (x < tot.length()){
            if(reverse_str.charAt(y) == tot.charAt(x)){
                y++;
                x++;
            }
            if(y == reverse_str.length()) {
                y = lps[y - 1];
            }


            else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
                palindrome += tot.charAt(x);
                if ( y!= 0){
                    y = lps[y-1];
                }
                else{
                    x += 1;
                }
            }
        }
        System.out.println(palindrome);
    }
}

Буду признателен за любую помощь. Я нахожу алгоритмы очень сложными, поэтому, пожалуйста, потерпите меня, если мой подход или код не соответствуют требованиям.

* Я исправил примеры входных и выходных данных, а также добавил свои результаты.


person Seyi Kareem    schedule 11.09.2019    source источник
comment
Вы уверены, что входные данные и ожидаемые результаты, которые вы перечислили, верны? Например, почему ввод 1221 должен приводить к выводу 12211221? Разве это не должно быть 1221221, поскольку это минимальное количество сложений, необходимых для создания палиндрома?   -  person Jordan    schedule 11.09.2019
comment
что должен вернуть computerelps(4321)?   -  person GabiM    schedule 11.09.2019
comment
вычисление(4321.) вернет [ 0, 0, 0, 0 ]   -  person Seyi Kareem    schedule 11.09.2019


Ответы (2)


Это помогает разделить эту проблему на более мелкие задачи, реализовать отдельный метод для каждой и проверить, работает ли каждый метод должным образом. Что действительно поможет вам, так это научиться использовать отладчик в вашей среде разработки. Но пока вы этого не сделаете, вы можете проверить, что каждая часть вашего кода работает должным образом. Поэтому я немного упростил ваш код и разделил его:

public static void main(String[] args){
        System.out.println("computelps " + ("[0, 0, 0, 0]".equals(Arrays.toString(computelps("4321"))) ? "works" : "doesn't work" ));   
        System.out.println("reverse " + ("4321".equals(reverse("1234")) ? "works" : "doesn't work" ));
        System.out.println("Solution " + ("1234321".equals(Solution("1234")) ? "works" : "doesn't work" ));
    }

    public static int[] computelps(String sample){
        int[] lps = new int[sample.length()];
        lps[0] = 0;
        int i = 1;
        int len = 0; // length of previous longest prefix suffix
        while (i < sample.length()) {
            if (sample.charAt(i) == sample.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            }
            else
            {
                if (len != 0) {
                    len = lps[len - 1];
                }
                else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        return lps;
    }

    public static String Solution(String line) {
        String newline = line.replace(".", "");
        String reverse_str = reverse(newline);

        int [] lps = computelps(reverse_str); // computes the lps of the pattern string

        // KMP Algorithm modified.

        return kpmModified(newline, reverse_str, lps);

    }

    private static String kpmModified(String newline, String reverse_str, int[] lps) {
        int x = 0; // index for total_string(tot)
        int y = 0; // index for pattern
        String tot = reverse_str + newline;
        String palindrome = newline;

        while (x < tot.length()){
            if(reverse_str.charAt(y) == tot.charAt(x)){
                y++;
                x++;
            }
            if(y == reverse_str.length()) {
                y = lps[y - 1];
            }


            else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
                palindrome += tot.charAt(x);
                if ( y!= 0){
                    y = lps[y-1];
                }
                else{
                    x += 1;
                }
            }
        }
        return palindrome;
    }

    private static String reverse(String newline) {
        String reverse_str = "";

        for (int i = newline.length() - 1; i >= 0; i--) {
            reverse_str += newline.charAt(i);
        }
        return reverse_str;
    }

И результат

computelps works
reverse works
Solution doesn't work

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

person GabiM    schedule 11.09.2019

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

Один пример. Пусть строка будет 12333. Если мы добавим каждый символ из индекса string.length() к 0, получится 1233333321, что неверно, так как дублируются тройки. Нам нужно игнорировать их, поэтому нам нужно добавить символы из string.length() - numOfDuplicateAtEnd в 0.

    public String palindromic(String num) {
        int i = num.length() - 1;
        while (i > -1 && num.charAt(i) == num.charAt(num.length() - 1))  
            i--;

        for (int k = i; k > -1; --k) 
            num += num.substring(k, k + 1);

        return num;
    }
person Will    schedule 11.09.2019
comment
Пожалуйста, постарайтесь сделать свой ответ более полным, предоставив некоторый код. - person francoisr; 11.09.2019