Минимальные циклические сдвиги (вперед или назад), которые необходимо выполнить для строки, чтобы сделать ее палиндромом

Ниже приведена постановка задачи и ее решение. Два тестовых примера провалились для меня. Помогите мне разобраться.

Строка называется палиндромной, если она одинаково читается с обоих концов. Учитывая строку S, вам разрешено выполнять циклические сдвиги. Более формально, вы можете выбрать любой символ с любого конца (голова или хвост) и добавить этот символ на другом конце. Например, если строка "abc", то если мы сделаем сдвиг, используя символ в позиции головы, тогда строка станет "bca". Точно так же, если мы делаем сдвиг, используя символ в хвосте, тогда входная строка становится "cab". Ваша задача — найти минимальное количество сдвигов, необходимых для того, чтобы данная строка стала палиндромом. В случае, если мы не можем преобразовать строку в палиндром, напечатайте -1.

Формат ввода: первая строка начинается с T, т.е. количества тестовых случаев, а затем следуют T строк, каждая из которых содержит строку S.

Формат вывода: Выведите минимальное количество циклических сдвигов для каждой строки, если ее можно сделать палиндромом, иначе -1.

Ограничения: 1<=T<=100, 1<=|S|<=300, S будут содержать только строчные буквы ('a'-'z').

Пример ввода и вывода

Вход

4
abbb
aaabb
aabb
abc

Выход

-1
1
1
-1

Объяснение: Для контрольного примера 2 (aaabb): сдвиньте символ с хвоста на голову, и результатом будет «баааб», то есть палиндром. Это операция, которая требует минимального количества сдвигов, чтобы данная строка стала палиндромом.

Для контрольного примера 3 (aabb): один из способов преобразовать заданную строку в палиндром — сдвинуть символ в начале к хвосту, и результатом будет "abba", то есть палиндром. Другой способ — сдвинуть символ с хвоста на голову, и в результате получится "baab", что тоже является палиндромом. Оба требуют только одну смену.

public class cyclic {

    static boolean flag = false;

    // fn to check if string is palindrome
    static boolean ispal(String s) {
        String reverse = "";
        int length = s.length();
        for (int i = length - 1; i >= 0; i--)
            reverse = reverse + s.charAt(i);
        reverse = reverse.trim();
        if (s.equals(reverse)) {
            flag = true;
            return true;
        } else {
            return false;
        }
    }

    // fn to perform front shift
    static int frontshift(String str) {
        int count = 0;
        String element = "";
        String s1[] = str.split("");
        Deque<String> dequeA = new LinkedList<String>();
        for (int i = 1; i < s1.length; i++) {
            dequeA.add(s1[i]);
        }
        while (!ispal(str)) {
            if (count <= str.length()) {
                element = "";
                String firstElement = dequeA.removeFirst();
                dequeA.addLast(firstElement);
                for (String object : dequeA) {
                    element = element + object;
                }
                str = element;
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    // fn to perform backshift
    static int backshift(String str) {
        int count = 0;
        String element = "";
        String s1[] = str.split("");
        Deque<String> dequeA = new LinkedList<String>();
        for (int i = 1; i < s1.length; i++) {
            dequeA.add(s1[i]);
        }
        while (!ispal(str)) {
            if (count <= str.length()) {
                element = "";
                String firstElement = dequeA.removeLast();
                dequeA.addFirst(firstElement);
                for (String object : dequeA) {
                    element = element + object;
                }
                str = element;
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    public static void main(String args[]) throws IOException {
        BufferedReader br =
                new BufferedReader(new InputStreamReader(System.in));
        List<Integer> list = new ArrayList<Integer>();
        int range = Integer.parseInt(br.readLine());
        for (int i = 0; i < range; i++) {
            String s = br.readLine();
            int l1 = frontshift(s);
            int l2 = backshift(s);
            if (flag == true) {
                if (l1 <= l2) {
                    list.add(l1);
                } else {
                    list.add(l2);
                }
            } else {
                list.add(-1);
            }
            flag = false;
        }
        for (Integer integer : list) {
            System.out.println(integer);
        }
    }
}

person J.Selva    schedule 21.08.2015    source источник
comment
Вы пытались отладить свое решение?   -  person TheLostMind    schedule 21.08.2015
comment
@TheLostMind да, я пробовал, и это работает для моих тестовых случаев. У тебя проблемы с запуском?   -  person J.Selva    schedule 21.08.2015
comment
Проблема в незнании того, что было на входе и каков ожидаемый результат.   -  person Peter Lawrey    schedule 21.08.2015
comment
Я вижу 2 вещи: 1. Почему вы вызываете reverse.trim()? 2. Почему ваш индекс начинается с 1, а не с 0?   -  person Codebender    schedule 21.08.2015
comment
@PeterLawrey Я почти уверен в ожидаемом результате. Они система проверяет около 15 тестовых случаев, только для двух она не удалась. Так что я думаю, что ввод является проблемой для меня.   -  person J.Selva    schedule 21.08.2015
comment
@Codebender Игнорировать reverse.trim(); и поскольку я использовал split(), который не имеет регулярного выражения, 0-й индекс был пуст. поэтому я получил доступ с 1.   -  person J.Selva    schedule 21.08.2015
comment
Вы видите результат своей программы? Как насчет регистрации ввода?   -  person Peter Lawrey    schedule 21.08.2015
comment
@PeterLawrey, да, я не вижу результата. Я не могу тебя понять. Введите целое число (количество строк), за которым следует n строк, для которых необходимо выполнить подсчет смен.   -  person J.Selva    schedule 21.08.2015
comment
@ J.Selva, я не думаю, что 0-й индекс будет пустым при разделении. Почему вы пришли к такому выводу?   -  person Codebender    schedule 21.08.2015
comment
Входные данные — это фактический текст, который читает ваша программа. Что именно?   -  person Peter Lawrey    schedule 21.08.2015
comment
@Codebender Я не использовал java8 при написании кода. Изменить: см. это для лучшего понимания ссылка   -  person J.Selva    schedule 21.08.2015
comment
@PeterLawrey Программа снова читает строку, извините, если я ошибаюсь.   -  person J.Selva    schedule 21.08.2015
comment
Что на самом деле читает br.readLine()? Это вход в вашу программу.   -  person Peter Lawrey    schedule 21.08.2015
comment
@PeterLawrey Я дам вам образцы входных данных. 1(количество вводимых строк) 1100(фактическая строка) Вывод: 1 (так как требуется одна смена)   -  person J.Selva    schedule 21.08.2015
comment
Этот код настолько неэффективен, что это причиняет боль. Зачем вы строите String, если вы можете проверить это сами, просто сравнив символы? Кроме того, если вы строите String шаг за шагом, используйте StringBuilder.   -  person fabian    schedule 21.08.2015
comment
@Fabian Спасибо за ваше предложение :)   -  person J.Selva    schedule 21.08.2015
comment
@ J.Selva, я удалил 1 из ввода: кажется, это не нужно. Пожалуйста, проверьте мое редактирование и восстановите его, если я ошибаюсь.   -  person Tagir Valeev    schedule 21.08.2015
comment
@TagirValeev Спасибо за редактирование. Я здесь новенький, и да, теперь он выглядит идеально, и да, 1 не понадобилось. Спасибо друг !   -  person J.Selva    schedule 21.08.2015
comment
И, например, 1100 какой результат вы получаете?   -  person Peter Lawrey    schedule 21.08.2015
comment
@PeterLawrey no 1 - это результат, так как его можно сделать палиндромом (0110) с одним сдвигом назад. Я отредактировал вопрос после ваших вопросов. сейчас недостаточно ясно?   -  person J.Selva    schedule 21.08.2015
comment
Я все еще жду, чтобы узнать, какой ввод дает неправильный результат, чтобы кто-нибудь мог воспроизвести проблему, с которой вы столкнулись.   -  person Peter Lawrey    schedule 21.08.2015


Ответы (1)


Я решил вашу задачу не на основе вашего кода:

import java.util.Scanner;

public class PalyndromeTest {
    static boolean isPalyndrome(String s, int shift) {
        int n = s.length();
        if(shift < 0) shift+=n;
        for(int pos = 0; pos < n/2; pos++) {
            if(s.charAt((pos+shift)%n) != s.charAt((n-pos-1+shift)%n))
                return false;
        }
        return true;
    }

    static int findShift(String s) {
        for(int shift = 0; shift <= s.length()/2; shift++) {
            if(isPalyndrome(s, shift) || isPalyndrome(s, -shift))
                return shift;
        }
        return -1;
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int count = s.nextInt();
        s.nextLine();
        for(int i=0; i<count; i++) {
            System.out.println(findShift(s.nextLine()));
        }
    }
}

Во-первых, isPalyndrome метод. Он проверяет, является ли строка палиндромом, а также работает с положительными или отрицательными сдвигами. Обратите внимание, что, например, для строки длиной 5 shift = -1 совпадает с shift = 4. Мы не создаем никаких новых строк, мы просто сканируем существующую, используя метод String.charAt. Мы используем оператор остатка % n для автоматического возврата к началу строки при достижении конца строки. Обратите внимание, что мы должны проверять только половину строки.

Во-вторых, метод findShift. Он просто перебирает все сдвиги от 0 до s.length()/2 (большие сдвиги проверять не нужно, поскольку они равны уже проверенным отрицательным сдвигам). На каждой итерации он проверяет как положительное, так и отрицательное смещение.

Наконец, метод main считывает стандартный ввод и вызывает findShift для каждой строки ввода. Он выводит результат сразу, хотя при желании вы можете собрать его в список и вывести в конце.

person Tagir Valeev    schedule 21.08.2015
comment
Я знаю, что мой код не оптимален. Я разместил этот код, потому что для этого я получил два неудачных теста. Я здесь, чтобы научиться анализировать этот код и генерировать тестовые примеры. И да, ваш код отлично работает, и он идеален. Можете ли вы выяснить логическую ошибку, если таковая имеется в опубликованном коде. - person J.Selva; 21.08.2015