Encontre o Maior Palíndromo em Java: 3 Algoritmos (Força Bruta, PD, Manacher)

Foto do autor

By luis

No universo da ciência da computação, uma sequência de caracteres que se mantém idêntica quando lida em ambas as direções (da esquerda para a direita ou vice-versa) é denominada palíndroma. A busca pela maior subsequência palíndroma dentro de uma string é um desafio clássico, que avalia a perícia e o entendimento de algoritmos de processamento textual.

Neste artigo, iremos explorar diversas estratégias para identificar e extrair a maior subcadeia palíndroma em strings, utilizando a linguagem de programação Java. Examinaremos abordagens eficazes e diretas, que evidenciam os recursos da linguagem e aprimoram a destreza na solução de problemas.

Estratégia da Força Bruta

A estratégia da força bruta analisa todas as subsequências concebíveis dentro da string, checando se cada uma delas é palíndroma. Isso é feito através da criação de todas as junções possíveis de índices de início e fim, e da verificação se a substring resultante é um palíndromo. Apesar de ser uma abordagem fácil de compreender, este algoritmo possui uma complexidade de tempo de O(n³), onde n representa o tamanho da string, o que o torna inviável para strings extensas.

Implementação em Java


public static String encontrarMaiorPalindromoForcaBruta(String str) {
    int n = str.length();
    String maiorPalindromo = "";

    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j <= n; j++) {
            String subString = str.substring(i, j);
            if (ehPalindromo(subString) && subString.length() > maiorPalindromo.length()) {
                maiorPalindromo = subString;
            }
        }
    }

    return maiorPalindromo;
}

private static boolean ehPalindromo(String str) {
    int i = 0;
    int j = str.length() - 1;

    while (i < j) {
        if (str.charAt(i) != str.charAt(j)) {
            return false;
        }
        i++;
        j--;
    }

    return true;
}

Abordagem da Programação Dinâmica

O método da programação dinâmica constrói uma tabela que armazena informações sobre se as subsequências em um dado intervalo de índices formam palíndromos. Ele inicia preenchendo a tabela com valores verdadeiros para as subsequências de tamanho 1 e, posteriormente, processa as subsequências mais longas, verificando se os caracteres nas extremidades são idênticos e se a substring entre eles é um palíndromo.

Implementação em Java


public static String encontrarMaiorPalindromoPD(String str) {
    int n = str.length();
    boolean[][] dp = new boolean[n][n];

    String maiorPalindromo = "";
    int maiorTamanho = 0;

    // Preenche a tabela com true para subsequências de tamanho 1
    for (int i = 0; i < n; i++) {
        dp[i][i] = true;
    }

    // Processa subsequências maiores
    for (int l = 2; l <= n; l++) {
        for (int i = 0; i <= n - l; i++) {
            int j = i + l - 1;

            if (str.charAt(i) == str.charAt(j) && (l == 2 || dp[i + 1][j - 1])) {
                dp[i][j] = true;

                if (l > maiorTamanho) {
                    maiorTamanho = l;
                    maiorPalindromo = str.substring(i, j + 1);
                }
            }
        }
    }

    return maiorPalindromo;
}

O Algoritmo de Manacher

O algoritmo de Manacher, também conhecido como algoritmo de expansão central, é uma estratégia linear eficaz para encontrar a maior subcadeia palíndroma. Ele gera um array que representa o raio de expansão máximo de cada caractere na string, levando em conta tanto palíndromos ímpares quanto pares.

Implementação em Java


public static String encontrarMaiorPalindromoManacher(String str) {
    int n = str.length();
    int[] p = new int[n];

    int centro = 0;
    int direita = 0;
    int maiorTamanho = 0;
    String maiorPalindromo = "";

    for (int i = 0; i < n; i++) {
        // Verifica se o caractere atual está dentro do alcance da expansão central
        int espelho = 2 * centro - i;
        if (direita > i) {
            p[i] = Math.min(direita - i, p[espelho]);
        }

        // Expande o palíndromo ao redor do caractere atual
        while (i - p[i] - 1 >= 0 && i + p[i] + 1 < n && str.charAt(i - p[i] - 1) == str.charAt(i + p[i] + 1)) {
            p[i]++;
        }

        // Atualiza o alcance da expansão central
        if (i + p[i] > direita) {
            centro = i;
            direita = i + p[i];
        }

        // Atualiza o maior palíndromo encontrado
        if (p[i] > maiorTamanho) {
            maiorTamanho = p[i];
            maiorPalindromo = str.substring(i - maiorTamanho, i + maiorTamanho + 1);
        }
    }

    return maiorPalindromo;
}

Conclusão

A busca pela maior subcadeia palíndroma em uma string é um problema recorrente, com diversas aplicações práticas. Apresentamos três algoritmos eficientes para solucionar este desafio: força bruta, programação dinâmica e Manacher.

O algoritmo de força bruta é simples, mas pouco eficaz para strings extensas. O algoritmo de programação dinâmica oferece uma solução mais eficiente, construindo uma tabela com informações sobre palíndromos. O algoritmo de Manacher é o método mais eficaz, utilizando uma abordagem de expansão central.

A escolha do algoritmo correto depende da dimensão da string e das exigências de desempenho. Para strings curtas, o algoritmo de força bruta pode ser suficiente. Para strings maiores, a programação dinâmica ou o algoritmo de Manacher são opções mais adequadas, sendo o algoritmo de Manacher o que oferece o melhor desempenho.

Perguntas Frequentes

1. Qual a complexidade de tempo do algoritmo de força bruta? O(n³)
2. Qual a complexidade de tempo do algoritmo de programação dinâmica? O(n²)
3. Qual a complexidade de tempo do algoritmo de Manacher? O(n)
4. Qual o melhor algoritmo para encontrar a maior subcadeia palíndroma em uma string grande? O algoritmo de Manacher.