Leetcode5. Longest Palindromic Substring(C++/Python)

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

题目大意:找最长的回文串,挺经典的一题,官方题解给了5种,这里有其中4种的C++版,有机会再更新。

Tips:

substr的用法:

          ①s.substr(start,length):从s的第i位开始,复制length长度;

          ②s.substr(start):从s的第i位开始,一直到s结束。

一、暴力法

时间O(n^3),空间O(1)

┭┮﹏┭┮通过时间127ms,虽然也能通过,还是尽量少用暴力吧,复杂度伤不起。

另外最外层的循环是用子字符串的串的长度作为变量,从最长的开始遍历,不要从0开始,这样找到得第一个满足条件的子字符串就可以了,能省点时间是一点emmmmm。

class Solution {
public:
    string longestPalindrome(string s) {
        string result;
        for(int len=s.length();len>0;len--){
            for(int i=0;(i+len)<=s.length();i++){
                bool flag=false;
                for(int j=0;j<=len/2;j++){
                    if(s[j+i]!=s[i+len-j-1])
                        break;
                    if(j==(len-1)/2)
                        flag=true;
                }
                if(flag==true)
                    return s.substr(i,len);
            }  
        }
        return result;
    }
};

二、中心扩展法(强推,容易理解)

时间O(n^2),空间O(n^2)

通过时间20ms!

中心扩展法,其实我个人总有一种他是暴力和Manacher算法的结合,它的本质也是挨个遍历,找最大的,但比起暴力的优点是他以每个字符为遍历对象,由该字符串向外扩展,找到以该字符串为中心的最长的回文串。

C++

class Solution {
public:
    string longestPalindrome(string s) {
        string ans = "", temp;
        for(int i = 0; i < s.length(); ++ i){
            temp = expandToCenter(s, i, i);
            ans = ans.length() > temp.length() ? ans : temp;
            temp = expandToCenter(s, i, i + 1);
            ans = ans.length() > temp.length() ? ans : temp;
        }
        return ans;
    }
    string expandToCenter(string s, int left, int right){
        while(left >= 0 && right < s.length() && s[left] == s[right]){
            -- left;
            ++ right;
        }
        return s.substr(left+1, right - left -1);
    }
};

Python

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        self.ans = ""
        self.s = s
        for i in range(len(s)):
            self.expandToCenter(i,i)
            self.expandToCenter(i,i+1)
        return self.ans
    def expandToCenter(self, left, right):
        while left >= 0 and right < len(self.s) and self.s[left] == self.s[right]:
            left -= 1
            right += 1
        temp = self.s[left+1:right]
        if len(self.ans) < len(temp):
            self.ans = temp

三、Manacher算法

时间O(n),空间O(n)

具体原理,有些地方我也没想太透,有兴趣可以找找相关资料。

具体代码如下:

C++

class Solution {
public:
    string longestPalindrome(string s) {
        if(s.length()==0)
            return s;
        string s1=INIT(s);
        string s2=Manancher(s1);
        s1="";
        for(int i=0;i<s2.length();i++){
            if(s2[i]!='#')
                s1+=s2[i];
        }
        return s1;
    }
    string INIT(string s){
        int len=s.length();
        string temp;
        temp+='@';
        for(int i=0;i<len;i++){
            temp+='#';
            temp+=s[i];
        }
        temp+="#$0";
        return temp;
    }
    string Manancher(string s){
        int len=s.length();
        std::vector<int> Len(len,0);
        int mx=0,po=0,ans=0;
        string result;
        for(int i=0;i<len;i++){
            if(mx>i)
                Len[i]=min(mx-i,Len[2*po-i]);
            else
                Len[i]=1;
            while(s[i-Len[i]]==s[i+Len[i]])
                Len[i]++;
            if(Len[i]+i>mx){
                mx=Len[i]+i;
                po=i;
            }
            if(Len[i]>ans){
                ans=Len[i];
                result=s.substr(i-Len[i]+1,2*Len[i]-1);
            }
        }
        return result;
    }
};

Python

class Solution(object):
    def longestPalindrome(self, s):
        if len(s) == 0:
            return s
        s1 = self.INIT(s)
        s2 = self.Manacher(s1)
        ans = ""
        for i in range(len(s2)):
            if s2[i] != "#":
                ans += s2[i]
        return ans
    def INIT(self, s):
        temp = "@"
        for i in range(len(s)):
            temp += '#'
            temp += s[i]
        temp += "#$0"
        return temp
    def Manacher(self, s):
        Len = [0] * (len(s))
        mx, po, ans = 0,0,0
        res = ""
        for i in range(len(s)):
            if mx > i:
                Len[i] = min(mx-i, Len[2*po-i])
            else:
                Len[i] = 1
            while (i+Len[i]) < len(s) and s[i-Len[i]] == s[i+Len[i]]:
                Len[i] += 1
            if Len[i] + i > mx:
                mx = Len[i] + i
                po = i
            if Len[i] > ans:
                ans = Len[i]
                res = s[i-Len[i]+1:i+Len[i]]
        return res

以下是manacher的核心算法

string s;//原字符串
string temp;//原字符串插入特殊字符
string result,tempresult;//最终结果子字符串
//形成temp字符串
void INIT(string s){
    int len=s.length();
    temp+='@';
    for(int i=0;i<len;i++){
        temp+='#';
        temp+=s[i];
    }
    temp+="#$0";
}
//核心算法
void Manacher(string s){
    int len=s.length();
    std::vector<int> Len(len,0);
    int mx=0,ans=0,po=0;
    for(int i=0;i<len;i++){
        Len[i]=mx>i? min(mx-i,Len[2*po-i]) : 1;
        while(s[i-Len[i]]==s[i+Len[i]])
            Len[i]++;
        if(Len[i]+i>mx){
            mx=Len[i]+i;
            po=i;
        }
        if(Len[i]>ans){
            ans=Len[i];
            tempresult=s.substr(i-Len[i]+1,2*Len-1);
        }
    }
}
int main(){
    INIT(s);
    Manacher(s);
    for(int i=0;i<tempresult.length();i++)
        if(tempresult[i]!='#')
            result+=tempresult[i];
}

四、动态规划

时间O(n^2),空间O(n^2)

dp[i][j]表示i-j的子字符串是否是回文串,初始化dp数组均为false,首先遍历s,将dp数组的对角线改为true,以及能构成两个字符长的子字符串的i处dp修改,再进行遍历时,k表示子字符串的长度,若从i开始的k个字符能构成回文串,则需要i+1处开始的k-2个字符能构成回文串,同时要i和i+k-1处的字符相等。

C++

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length(), cnt = 1;
        if(len == 0)
            return s;
        vector<vector<bool>> dp(len, vector<bool>(len, false));
        string ans = s.substr(0, 1);
        for(int i = 0; i < len; ++ i){
            dp[i][i] = true;
            if(i < len - 1 && s[i] == s[i+1]){
                if(cnt == 1)
                    ans = s.substr(i, ++cnt);
                dp[i][i+1] = true;
            }
        }
        for(int k = 3; k <= len; ++ k){
            for(int i = 0; i + k <= len; ++ i)
                if(s[i] == s[i+k-1] && dp[i+1][i+k-2]){
                    if(cnt < k){
                        cnt = k;
                        ans = s.substr(i, cnt);
                    }
                    dp[i][i+k-1] = true;
                }
        }
        return ans;
    }
};

Python

class Solution(object):
    def longestPalindrome(self, s):
        Len = len(s)
        if Len == 0:
            return s
        dp = [[False] * Len for i in range(Len)]
        ans = "" + s[0]
        for i in range(Len-1):
            dp[i][i] = True
            if(s[i] == s[i+1]):
                dp[i][i+1] = True
                if(len(ans) == 1):
                    ans = s[i:i+2]
        dp[Len-1][Len-1] = True
        for k in range(3,Len+1):
            for i in range(Len+1-k):
                if dp[i+1][i+k-2] and s[i] == s[i+k-1]:
                    dp[i][i+k-1] = True
                    if k > len(ans):
                        ans = s[i:i+k]
        return ans
        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值