zoukankan      html  css  js  c++  java
  • LeetCode5:最长回文子串

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

    示例 1:

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

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

    这题有4种解法,暴力解法,中心扩散法,动态规划,manacher算法。暴力算法不做解释,manacher太高深,先不学了。

    中心扩散法

    从边界情况,即子串长度为1或者2的情况向两边扩散,如果两边相同就可以加长回串的长度,最后返回最长的子串。

     1 class Solution {
     2 public:
     3     pair<int, int> expandAroundCenter(const string& s, int left, int right) {
     4         while (left >= 0 && right < s.size() && s[left] == s[right]) {
     5             --left;
     6             ++right;
     7         }
     8         return {left + 1, right - 1};
     9     }
    10 
    11     string longestPalindrome(string s) {
    12         int start = 0, end = 0;
    13         for (int i = 0; i < s.size(); ++i) {
    14             auto [left1, right1] = expandAroundCenter(s, i, i);
    15             auto [left2, right2] = expandAroundCenter(s, i, i + 1);
    16             if (right1 - left1 > end - start) {
    17                 start = left1;
    18                 end = right1;
    19             }
    20             if (right2 - left2 > end - start) {
    21                 start = left2;
    22                 end = right2;
    23             }
    24         }
    25         return s.substr(start, end - start + 1);
    26     }
    27 };
    28 
    29 作者:LeetCode-Solution
    30 链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
    31 来源:力扣(LeetCode)
    32 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    长度为1的中心子串有n个,长度为2的中心子串有n-1个,每个中心子串扩展都是O(n)次,时间复杂度为O(n^2),空间复杂度为O(1)。

    动态规划

    动态规划在于找到状态转移方程。如果一个子串是回文串,而且该串的两侧的两个字符是相同的,那么加上两次的字符的新串也是回文串。

    转移方程可以写成如下形式:

     而对于边界条件,要么中心子串是一个字符,要么是两个相同的字符。

     1 class Solution {
     2 public:
     3     string longestPalindrome(string s)
     4     {
     5         if(s.size()==0) return s;
     6         int n = s.size();
     7         vector<vector<int>> dp(n, vector<int>(n));
     8         int maxlen = 0, maxi = 0, maxj = 0;
     9         
    10         dp[0][0]=1;
    11 
    12         for (int j = 1; j < n; j++)
    13         {   
    14             dp[j][j]=1;
    15             dp[j-1][j]=(s[j-1]==s[j])?2:0;
    16             if(dp[j-1][j]>maxlen){
    17                 maxlen = dp[j-1][j];
    18                 maxi = j-1;
    19                 maxj = j;
    20             }
    21             for (int i = 0; i < j-1; i++)
    22             {
    23                 if ((s[i] == s[j]) && ((dp[i + 1][j - 1] != 0) || (j - i < 3)))
    24                 {
    25                     dp[i][j] = dp[i + 1][j - 1] + 2;
    26                     if (dp[i][j] > maxlen)
    27                     {
    28                         maxlen = dp[i][j];
    29                         maxi = i;
    30                         maxj = j;
    31                     }
    32                 }
    33                 else
    34                     dp[i][j] = 0;
    35             }
    36         }
    37         return s.substr(maxi, maxj-maxi+1 );
    38     }
    39 };

    这里采用给一个上三角的n*n的二位数组记录这个位置横纵坐标(i,j)对应的子串(即从i到j)是否为回文串,如果不是则为0,如果是则代表该回文子串的长度。

    因为(i,j)是否为回文取决于(i+1,j-1),所以需要先计算出每一个位置左下方的值,才能得出当前位置的值。边界条件即为[i][i]位置全为1,[i-1][i]位置的值取决于这两个位置的字符是否相同。

    循环按照按列循环的顺序进行,一共进行n-1次列循环,对于每列进行n-2次行循环,时间复杂度为O(n^2),空间复杂度为O(n^2)。

  • 相关阅读:
    Rational Rose 2003 逆向工程转换C++ / VC++ 6.0源代码成UML类图
    用VC实现特定编辑框上对回车键响应
    22.职责链模式
    21.策略模式
    20.状态模式
    19.解释器模式
    18.备忘录模式
    17.中介者模式
    16.观察者模式
    15.迭代器模式
  • 原文地址:https://www.cnblogs.com/rookiez/p/13175192.html
Copyright © 2011-2022 走看看