最长回文子串 c++

解法 1:

将字符串 s 反转得到字符串 rev,再求他们的最长公共子串,再判断该最长公共子串是否就是我们要找的最长回文子串。

class Solution {
public:
    string longestPalindrome(string s) {
        if(s.length()==1) return s;//大小为1的字符串必为回文串
        string rev=s;//rev存放s反转结果
        string res;//存放结果
        std::reverse(rev.begin(),rev.end());
        if(rev==s) return s;
        int len=0;//存放回文子串的长度
        for(int i=0;i<s.length();i++)//查找s与rev的最长公共子串
        {
            string temp;//存放待验证子串
            for(int j=i;j<s.length();j++)
            {
                temp=temp+s[j];
                if(len>=temp.length())
                    continue;
                else if(rev.find(temp)!=-1)//在rev中找到temp
                {
                    string q=temp;//q用来验证temp是否是回文子串
                    std::reverse(q.begin(),q.end());
                    if(q==temp)
                    {
                        len=temp.length();
                        res=temp;
                    }
                }
                else break;
            }
            temp="";
        }
        return res;
    }
};

注:该方法虽然比暴力法高效,但是在查找最长公共子串的部分效率还是不够高,所以在力扣中最后一个测试用例会超出时间限制。

解法2:

思路:
对于这道题,我们需要判断多个子串是否是回文子串,在判断的过程中会有重复的字串判断,所以为了,减少判断时间复杂度,我们从暴力递归,改造成动态规划的形态。
首先我们定义一个二维数组dp,行和列分别代表字符串s每个字符的下标,例如dp[j][i] 代表从下标为j到i之间的子串,是否为回文子串,如果是记录下为true,否则为false,
这样就可以把之前判断过的记录下来,当判断dp[j-1][i+1]的时候,当s[j-1]=s[i+1]时,我们只需要判断dp[j][i]是否为回文子串即可,因为dp[j][i]之前已经判断过,所以不用再进入j到i这个范围内判断j到i是否是回文子串。
我们再用本题中的例子具体演示一下,方便理解:
当i=1, j=0时,s[j]=b,s[i]=a,所以dp[0][1]=false;
当i=2,j=0时,s[j]=b,s[i]=b,这时候我们要判断s[0+1]=s[2-1]?显然相等,所以dp[j][i]=true;
当i=3,j=0时,s[j]=b,s[i]=a,不相等,j++,s[1]=a=s[3],同理此时判断s[1+1]=s[3-1]?显然相等。
总之就是让列表示的下标走在前面,然后用行表示的下标,判断列之前的每一字符的位置到它之间是否回文,其中判断的过程一定会有重复的判断,而这些重复的也一定是在之前的循环过程中被判断过,所以不用再进入子串的子串中进行判断。

class Solution {
public:
    string longestPalindrome(string s) {
    int length=s.length();
   if(length<=1)
   {
       return s;
   }
   vector<vector<int>>res (length,vector<int>(length,0));
    //先初始化二维数组(对角线)
   for(int i=0;i<length;i++)
    {
        res[i][i]=1;
    }
    int start=0;//记录最大回文子串的开始位置
    int maxlength=1;//记录最大回文子串的长度
    for(int i=1;i<length;i++)//两层for循环遍历每一个位置到另一个位置的情况
    {
        for(int j=0;j<i;j++)
        {
            if(s[i]==s[j])
            {
                if(i-j<3)//如果如果两个相等字符之间只有一个字符,那么一定回文
                {
                    res[j][i]=1;
                }
                else
                {
                    res[j][i]=res[j+1][i-1];
                }
            }
            if(res[j][i])//当j到i之间的子串回文时判断其长度是否最大,然后更改
            {
                if(i-j+1>maxlength)
                {
                    maxlength=i-j+1;
                    start=j;
                }
            }

        }
    }
    return s.substr(start,maxlength);
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章