题目:最长回文子串(C++)

看到这个题第一反应是做过啊,然后就开始写,等写完一测。emmmmm,原来是最长回文子串不是最长回文子序列,但是写都写了,我就把代码稍微修改了一下让适应于该题目,代码如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s)
    {
        int n     = s.length();
        if (n == 1 || n == 0)
            return s;
        int max   = 0;
        int begin = 0;
        vector<vector<int> > dp(n,vector<int>(n));
        for (int j = 0; j < n; j++)
        {
            dp[j][j] = 1;
            for (int i = j - 1; i >= 0; i--)
            {
                if (s[i] != s[j])
                    continue;
                if (dp[i + 1][j - 1] == 0 && i != j - 1)
                    continue;
                dp[i][j] = dp[i + 1][j - 1] + 2;
                if (max >= dp[i][j])
                    continue;
                max   = dp[i][j];
                begin = i;
            }
        }
        if (max == 0)
            return s.substr(begin, 1);
        else
            return s.substr(begin, max);
    }
};

然后这个代码一看就很搓啊,完全不适应该题,猜测效率一定很低,等提交过后看,果不其然,只超过了13.74%的代码。只好删了重写。

第二次写的代码效率超过了32.9%代码如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s)
    {
        int n = s.length();
        if (n == 1 || n == 0)
            return s;
        int max      = 0;
        int diff     = 0;
        int begin    = 0;
        int end      = 0;
        int maxBegin = 0;
        int maxEnd   = 0;
        for (int i = 0; i < n; ++i)
        {
            for (int j = n - 1; j > 0; --j)
            {
                if (max > j - i)
                    break;
                begin = i;
                end   = j;
                while (s[begin] == s[end] && begin <= end)
                {
                    ++begin;
                    --end;
                }
                if (end < begin && begin - end < 3)
                {
                    diff = j - i;
                    if (max < diff)
                    {
                        max      = diff;
                        maxBegin = i;
                        maxEnd   = j;
                    }
                }
            }
            if (max > n - i - 1)
                break;
        }
        return s.substr(maxBegin, max + 1);
    }
};

好吧我感觉这个应该是我能想出来的最优解法了,之后我看了一下网站上的解法。其中

倒数第二个的解法是这样的

class Solution {
public:
    string longestPalindrome(string s) {
        int len   = 0;
        int left  = 0;
        int right = 0;
        string result = "";

        int i = 0;
        while(i < s.size())
        {
            left  = i;
            right = i;
            while (right + 1 < s.size() && s[right] == s[right + 1])
                right++;
            i = right + 1;
            while (left >= 0 && right < s.size() && s[left] == s[right])
            {
                left--;
                right++;
            }
            if (len < right - left - 1)
            {
                len    = right - left - 1;
                result = s.substr(left + 1, len);
            }
        }

        return result;
    }
};

厉害了我的哥,你没优化输入输出流,然后在求结果字符串时还多次分割影响效率,竟然能达到6ms执行速度排第二。

我看了这位大神的代码,发现主要思路是从一个中心下标开始向两边检测,然后这里他用了一个巧妙得方法来处理偶数长度字符串要从两个字符开始的情况,即,选定中心后,循环检测之后的字符是否与选定的字符相等如果相等,则+1。这样如果出现偶数长度的字符串,开始时left和right指向相邻的两个字符。我把这个大神代码加了一下速,然后丢到了leetcode上检测,修改后的代码如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s)
    {
            int len = 0;
    int left = 0;
    int right = 0;
    int maxRes = 0;
    int leftRes = 0;

    int i = 0;
    while(i < s.size())
    {
        left = i;
        right = i;
        while (right + 1 < s.size() && s[right] == s[right + 1])
            right++;
        i = right + 1;
        while (left >= 0 && right < s.size() && s[left] == s[right])
        {
            left--;
            right++;
        }
        if (len < right - left - 1)
        {
            len = right - left - 1;
            leftRes = left;
            maxRes = len;
        }
    }

    return s.substr(leftRes + 1, maxRes);
    }
};

然后检测结果显示如下:

超过了100%并且显示执行速度为0ms,厉害了。

之后大致看了看之前排第一的算法,发现是用“#”把字符填充为原来的2n+1再从中心字符进行演算,完全没这位哥的巧妙,这里就不提了。

原文地址:https://www.cnblogs.com/change4587/p/9153648.html

时间: 2024-10-08 10:41:54

题目:最长回文子串(C++)的相关文章

九度oj 题目1528:最长回文子串

题目描述: 回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. 回文子串,顾名思义,即字符串中满足回文性质的子串. 给出一个只由小写英文字符a,b,c...x,y,z组成的字符串,请输出其中最长的回文子串的长度. 输入: 输入包含多个测试用例,每组测试用例输入一行由小写英文字符a,b,c...x,y,z组成的字符串,字符串的长度不大于200000. 输出: 对于每组测试用例,输出一个整数,表示该组测试用例的字符串中所包含的的最长回文子串的长度. 样例输入:

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

[C++]LeetCode: 99 Longest Palindromic Substring (最长回文子串)

题目:Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 思路:题目要求的s的一个最长回文子串.暴力解决办法就是枚举所有的子串,再对每个子串进行回文判断.进行剪枝,我们考虑可以使用动态规划来避免重复的判

URAL 1297 后缀数组:求最长回文子串

思路:这题下午搞了然后一直WA,后面就看了Discuss,里面有个数组:ABCDEFDCBA,这个我输出ABCD,所以错了. 然后才知道自己写的后缀数组对这个回文子串有bug,然后就不知道怎么改了. 然后看题解,里面都是用RMQ先预处理任意两个后缀的最长公共前缀,因为不太知道这个,所以又看了一下午,嘛嘛-- 然后理解RMQ和后缀一起用的时候才发现其实这里不用RMQ也可以,只要特殊处理一下上面这个没过的例子就行了,哈哈--机智-- 不过那个国家集训队论文里面正解是用RMQ做的,自己还得会和RMQ一

leetcode 5 :Longest Palindromic Substring 找出最长回文子串

题目: Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. 翻译: 找出字符串s中最长的回文子串,字符串s的最长是1000,假设存在唯一的最长回文子串 法一:直接暴力破解 O(N3)的时间复杂度,运行超

(算法)最长回文子串

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

最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和

参考:http://www.ahathinking.com/archives/124.html 最长公共子序列 1.动态规划解决过程 1)描述一个最长公共子序列 如果序列比较短,可以采用蛮力法枚举出X的所有子序列,然后检查是否是Y的子序列,并记录所发现的最长子序列.如果序列比较长,这种方法需要指数级时间,不切实际. LCS的最优子结构定理:设X={x1,x2,……,xm}和Y={y1,y2,……,yn}为两个序列,并设Z={z1.z2.……,zk}为X和Y的任意一个LCS,则: (1)如果xm=

Ural 1297 Palindrome 【最长回文子串】

最长回文子串 相关资料: 1.暴力法 2.动态规划 3.中心扩展 4.Manacher法 http://blog.csdn.net/ywhorizen/article/details/6629268 http://blog.csdn.net/kangroger/article/details/37742639 在看后缀数组的时候碰到的这道题目 不过没用后缀数组写出来= = 用了一个很暴力的做法卡进了1 s Source Code: //#pragma comment(linker, "/STAC