leetcode题库5-- 最长回文子串

本文探讨了在给定字符串中查找最长回文子串的算法,包括动态规划、中心扩展及马拉车算法(Manacher’s Algorithm)。动态规划通过状态转移方程实现,中心扩展利用回文对称性,马拉车算法则结合了两者的优势。

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:

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

思路
动态规划: 主要是要状态转移方程
P(i,j)=(P(i+1,j−1)&&S[i]==S[j]),其中由于p(i,j)之前要知道p(i+1,j-1),因此遍历时采用由后往前遍历。
回文子串长度为1和2时,单独考虑。

string longestPalindrome(string s) {
        int len = s.size();
        vector<vector<int>> dp(len, vector<int>(len));
        string res = "";

        //p(i,j) = (p(i+1,j-1) && s[i] == s[j])   
        for(int i = len-1; i >=0; i--)
        {
            for(int j = i; j < len; j++)
            {
                dp[i][j] = (s[i] == s[j]) && (j - i < 2 || dp[i+1][j-1]);

                //比较长度
                if(dp[i][j] && j-i+1 > res.size())
                {
                    res = s.substr(i, j-i+1);
                } 
            }
        }

        return res;
    }

其它方法
中心扩展
因为回文字符串是中心对称的。因此以各中心向两边扩展比较是否相等,判断是否是回文。包含奇数和偶数一共有n+n-1个中心;
Manacher’s Algorithm 马拉车算法
其思想也是利用了中心扩展法,不过在它的基础上充分利用了回文特点。先将原字符串进行变换,如下

原字符串:    abc
改变后:     #a#b#c#

其次重点理解maxRight,center这两个变量。
  maxRight 是指已出现的回文字符串最右边字符的索引。center是对于的回文中心。这两者是一一对应的。
  在遍历过程中,当遍历到 i 时,需要判断 i 和 maxRight的大小。
  i >= maxRight  这时,只需按照中心扩展法即可
  i < maxRight  因为回文对称的特点,找到 i 对关于center对称的点 mirror , p[mirror]为扩展步数。如果 p[mirror]+i < maxRight ,p[i] = p[mirror] (注:i 和 mirror 是镜像对称的,在没超出center 为 中心的回文字符串时,因此 mirror 点是回文长度等于 i 点)。否则p[i] 暂时等于maxRight-i。后面继续中心扩展计算。

string longestPalindrome(string s) {
        //变换字符串,插入'#'
        int len = s.size();
        string news = "#";
        for(int i = 0; i < len; ++i)
        {
            news += s[i];
            news += '#';
        }

        int slen = 2* len +1;       //变化后字符串的长度
        int maxRight= 0;            //回文右边扩展最大的索引
        int center = 0;             //回文中心

        int start = 0;              //原字符串回文起始位置
        int maxLen = 1;             //回文字符串的长度

        int* p = new int[slen];

        for(int i = 0; i < slen; i++)
        {
            p[i] = 0;
        }

        for(int i = 0; i < slen; ++i)
        {
            if(i < maxRight)
            {
                //找到i 关于center 对称的点
                int mirror = 2 * center -i;
                p[i] = min(maxRight-i, p[mirror]);       //需要理解
            }

            int left = i - (1+p[i]);
            int right = i + (1 + p[i]);

            while(left >= 0 && right < slen && news[left] == news[right] )  //注意边界
            {
                p[i]++;
                left--;
                right++;
            }

            //判断maxRight是否更新
            if(i+p[i] > maxRight)
            {
                maxRight = i+p[i];
                center = i;
            }

            //比较回文长度
            if(p[i] > maxLen)
            {
                maxLen = p[i];
                start = (i-maxLen)/2;
            }
                
            
        }

        return s.substr(start, maxLen);




    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值