Алгоритм для дублированных, но перекрывающихся строк

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

Однако два вхождения s могут перекрываться. Например,

  • aba возвращает ababa
  • xxxxx возвращает xxxxxx
  • abracadabra возвращает abracadabracadabra

Мой код до сих пор таков:

import java.util.Scanner;

public class TwiceString {

    public static String getShortest(String s) {
        int index = -1, i, j = s.length() - 1;
        char[] arr = s.toCharArray();
        String res = s;

        for (i = 0; i < j; i++, j--) {
            if (arr[i] == arr[j]) {
                index = i;
            } else {
                break;
            }
        }

        if (index != -1) {
            for (i = index + 1; i <= j; i++) {
                String tmp = new String(arr, i, i);
                res = res + tmp;
            }
        } else {
            res = res + res;
        }

        return res;
    }

    public static void main(String args[]) {
        Scanner inp = new Scanner(System.in);
        System.out.println("Enter the string: ");
        String word = inp.next();

        System.out.println("The requires shortest string is " + getShortest(word));
    }
}

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

Ответы

Ответ 1

Используйте дерево суффиксов . В частности, после того, как вы построили дерево для s, перейдите к листу, представляющему всю строку, и поднимитесь до тех пор, пока не увидите другой маркер конца строки. Это будет лист самого длинного суффикса, который также является префиксом s.

Ответ 2

Как уже говорилось в @phs, часть проблемы может быть переведена на "найти самый длинный префикс s, который также является суффиксом s", и решение без дерева может быть следующим:

public static String getShortest(String s) {
    int i = s.length();
    while(i > 0 && !s.endsWith(s.substring(0, --i))) 
        ;
    return s + s.substring(i);
}

Ответ 3

После того, как вы нашли свой индекс и даже если он -1, вам просто нужно добавить к исходной строке подстроку, идущую от index + 1 (так как индекс является последним совпадающим символьным индексом) до конца строки, Там есть метод в String, чтобы получить эту подстроку.

Ответ 4

Думаю, вам стоит взглянуть на алгоритм Knuth-Morris-Pratt, таблица частичного соответствия, которую он использует, в значительной степени зависит от того, что вам нужно (и, кстати, это очень хороший алгоритм;)

Ответ 5

Если ваша строка ввода s есть, скажем, "abcde", вы можете легко создать регулярное выражение, как показано ниже (обратите внимание, что последний символ "e" отсутствует!):

a(b(c(d)?)?)?$

и запустите его в строке s. Это вернет исходную позицию задней повторяющейся подстроки. Затем вы просто добавили недостающую часть (т.е. Последние N-M символы s, где N - длина s, а M - длина совпадения), например

aba
  ^ match "a"; append the missing "ba"
xxxxxx
 ^ match "xxxxx"; append the missing "x"
abracadabra
       ^ match "abra"; append the missing "cadabra"
nooverlap
--> no match; append "nooverlap"

Ответ 6

Из моего понимания вы хотите это сделать:

input: dog
output: dogdog
--------------
input: racecar
output: racecaracecar

Так вот как я бы это сделал:

 public String change(String input)
{
    StringBuilder outputBuilder = new StringBuilder(input);

    int patternLocation = input.length();
    for(int x = 1;x < input.length();x++)
    {
        StringBuilder check = new StringBuilder(input);

        for(int y = 0; y < x;y++)
            check.deleteCharAt(check.length() - 1);

        if(input.endsWith(check.toString()))
        {
            patternLocation = x;
            break;
        }
    }

    outputBuilder.delete(0,  input.length() - patternLocation);

    return outputBuilder.toString();
}

Надеюсь, это помогло!