最長迴文子串 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);
  }

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