算法练习——最长回文子串

题目:

给定一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

方法1:暴力求解

思路:可以通从两端到中间遍历字符串,如果碰到字符串是回文串,则该回文串一定是是最长回文串。

效果:判断的整个过程其实有三个内部循环,时间复杂度接近  O(n^3) ,空间复杂度O(n)

public class LongestPalindrome1 {

    //利用两个for循环来遍历所有的子串,并且在里面再加一层while循环用于判断字符串是否是回文串
    public String longestPalindrome(String s) {
        for (int size = s.length(); size > 0; size--) {
            for (int low = 0, hight = low+size-1; hight < s.length(); low++,hight++) {
                if (isPalindrome(s,low,hight)) {
                    return s.substring(low, hight+1);
                }
            }
        }
        return s.substring(0, 1);
    }

    //判断一个字符串是否是回文字符
    private boolean isPalindrome(String s, int low, int hight) {
        while (low < hight) {
            if(s.charAt(low) == s.charAt(hight)){
                low++;
                hight--;
            }else {
                return false;
            }
        }
        return true;
    }
}

方法2:动态规划思想

思路:如果s(i,j)是回文串,则table[i][j] = true;否则定义为false。如何计算table[i][j]呢,我们可以首先检查table[i+1][j-1]是否为true,及s[i]是否等于s[j]。

--------------------------------------------------这个思想其实和前面的求解最长公共子序列很像。

效果:时间复杂度O(n^2),空间O(n^2)

public class LongestPalindrome {
    public static String longestPalSubstr(String s){

        int n = s.length();

        boolean[][] table = new boolean[n][n];

        //所有的一个字符肯定是回文串
        int maxLength = 1;

        //组成的boolean矩阵的对角都肯定为true
        for (int i = 0; i < n; i++) {
            table[i][i] = true;
        }

        int start = 0;

        //如果字符串长度小于2,则直接处理
        for (int i = 0; i < n - 1; ++i) {
            if (s.charAt(i) == s.charAt(i +1)) {
                table[i][i+1] = true;
                start = i;
                maxLength = 2;
            }
        }

        //如果字符串长度大于2,则开始遍历处理,主要是通过两层for循环

        //检查字符串长度大于2的字符串,其中k表示子字符串的长度
        for (int k = 3; k <= n; ++k) {

            //i表示子字符串中起始的位置
            for (int i = 0; i < n - k + 1; i++) {

                //获取子字符串结束的位置,
                int j = i + k - 1;

                if (s.charAt(i) == s.charAt(j) && table[i+1][j-1]) {
                    table[i][j] = true;
                    if (k > maxLength) {
                        maxLength = k;
                        start = i;
                    }
                }
            }
        }
        return s.substring(start, start+maxLength);
    }
}

方法3:分奇偶中心讨论

思路:以某个元素为中心,分别计算偶数长度的回文最大长度和奇数长度的回文最大长度。

奇数有一个中心,偶数有两个中心点,从中心点向两端判断,找出最长的回文子串。

效果:时间复杂度O(n^2),空间O(1)

public class LongestPalindrome {

    public static String longestPalSubstr(String s){
        //最后字符串的长度
        int maxLength = 1;  

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

        int low ,hight;

        //这里面用i表示中心点的位置
        for (int i = 0; i < len; i++) {

            //首先查找最长的偶数回文字符串,有两个中心点,分别为 i -1、 i
            low = i -1;
            hight = i;
            while (low >= 0 && hight < len && s.charAt(low) == s.charAt(hight)) {
                if (hight - low + 1 > maxLength) {
                    maxLength = hight - len + 1;
                    start = low;
                }
                --low;
                ++hight;
            }

            //其次寻找最长的奇数的最长回文字符串,中心点以i为主
            low = i - 1;
            hight = i + 1;
            while (low >= 0 && hight < len && s.charAt(low) == s.charAt(hight)) {
                if (hight - low + 1 > maxLength) {
                    maxLength = hight - low + 1;
                    start = low;
                }
                --low;
                ++hight;
            }
        }

        //起始和结束的位置
        return s.substring(start, start + maxLength);
    }
}

原文地址:https://www.cnblogs.com/xiaxj/p/9613842.html

时间: 2024-11-13 03:28:14

算法练习——最长回文子串的相关文章

[算法]manachar最长回文子串

现给定一个已知的字符串str[],现在想要在O(n)的时间复杂度之内求出一个最长的回文子字符串(正着和倒着顺序读一致). Manacher最早发现了可以用O(n)的时间复杂度来解决该问题,所以这种方法称之为Manacher算法. #include <iostream> using namespace std; int min(int a, int b){ return a > b ? b : a; } char* preproccess(char* src, char* des){ in

数据结构--Manacher算法(最长回文子串)

在字符串中求出其最长回文子串 可能是奇回文也可能是偶回文,要考虑全面 暴力解法:(因为存在奇回文和偶回文的问题,所以不好找,有一个技巧,就是想字符串中每个字符之间添加一个符号(任意符号,也可以是字符串中的符号),然后在每个位置向两端开始扩充) 答案就是最大值/2 Manacher算法: 字符串中每个字符串之间也要加上一个字符 回文直径:从某个位置开始向两边扩的最大长度 1. 回文半径数组:arr[],以每个位置为中心能扩出来的回文半径的长度 2. 最右回文右边界R:所有回文半径中,最靠右的位置

(算法)最长回文子串

题目: 求一个字符串的最长回文子串 思路: 1.暴力枚举 最容易想到的就是暴力破解,列举每一个子串,然后根据回文的定义判断是不是回文,找到最长的那个. 求每一个子串的时间复杂度为O(N^2),判断子串是不是回文的时间复杂度为O(N),所以时间复杂度为O(N^3). 2.动态规划 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串.这样最长回文子串就能分解成一系列子问题了. 这样需要额外的空间是O(N^2),时间复杂度也是O

【算法】最长回文子串的判断

描述: 比如:"12212321"的最长回文子串为"12321"长度为5 <pre name="code" class="cpp">int LongestPalindrome(string s) { int max=0; if (s.length() >= 1) { for(int i=0;i<s.length();i++) { int l; for(l=0;(i-l>=0 &&

算法题--最长回文子串

题目描述 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设?s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案. 示例 2: 输入: "cbbd" 输出: "bb" 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/longest-palindromic-substring

【算法】最长回文子串 longest palindrome substring

对于字符串S, 要找到它最长的回文子串,能想到的最暴力方法,应该是对于每个元素i-th都向左向右对称搜索,最后用一个数组span 记录下相对应元素i-th为中心的回文子串长度. 那么问题来了: 1. 这样的方法,对于奇回文子串和偶回文子串的处理不一样,比如所"acbca" 和"acbbca" 2. 计算冗余,e.g. "sscssabcccchccccba"中, 自左向右遍历计算的话,会发现, "abcccchccccba"是

Manacher算法解决最长回文子串长度问题

马拉车(Manacher)算法(具体算法流程看这个哥们的:https://blog.csdn.net/qq_35065720/article/details/104205920): 算法解决:在一个字符串中找到最长的回文字符串. 实现策略: 以每个位置作为中心,向两边扩展,可以确定奇回文,但是偶回文无法这样做. 解决方法:在字符串中间及两边插入某种字符,此时可以按照这种方法进行扩展.此时无论奇回文还是偶回文都可以找到. 例如11211,此时添加任意字符在两边#1#1#2#1#1#此时均可以进行回

Manacher算法----最长回文子串

题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的.同时,奇数和偶数长度还要分别考虑. Manacher算法可以解决上述问题,并在O(n)时间复杂度内求出结果.下面我们来看一下Manacher算法. 首先,为了处理奇偶的问题,在每个字符的两边都插入一个特殊的符号,这样所有的奇数或偶数长度都转换为奇数长度.比

[hiho 01]最长回文子串、Manacher算法

题目描述 - 基础方法:枚举子串,判断是否为回文串. - 改进:枚举中间位置,向两侧拓展. - 再改进:利用以前的信息,使得不用每个新位置都从长度1开始拓展. - 优化:将字符串预处理为奇数长度以避免考虑条件分支. - 再优化:开头加入特殊字符避免考虑边界. Manacher 算法: id 是中心点,mx 是其边界.P[i] 表示以 i 为中心的最长回文子串的折半长度. 只要 i < mx, 以 i 为中心的回文子串就可以不必从长度1开始找,而从min{P[j], mx - i}开始(其中j为i