leetcode---(5).最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串
示例:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案

输入:s = "cbbd"
输出:"bb"

看到题目的第一个想法就是用栈来实现。但是栈碰上奇数个的时候,怎么解决该不该弹出。还有栈什么时候弹出。比如abbabba。想了一阵没有解决的办法。
只好蛮力法,俩个指针输出所有的(比现在最长回文串还长的)串,再调用判断是不是回文。如果是回文,就记录下最大那个。时间复杂度太高了O(n3)。

(0).蛮力法

//蛮力法:输出所有的字符串,检查它是不是回文
class Solution {
public:
    string longestPalindrome(string s) {
        if(s.length() < 2)
            return s;
        int begin = 0,maxsize = 1;
        for(int i = 0;i < s.length()-1;i++){
            for(int j = i + 1;j < s.length();j++){
                if((j-i+1)> maxsize && isabcba(s,i,j)){
                    begin = i;
                    maxsize = j-i+1;
                }
            }
        }
        return s.substr(begin,maxsize);
    }

    bool isabcba(string s,int start,int end){
        while(end > start){
            if(s[start] != s[end])
                return false;
            start++;
            end--;
        }
        return true;
    }
};

太丢人了,我这个代码在leetcode中的一个例程中超过leetcode的时间限制了。
看看官方的答案吧。

(1).中心扩散O(n2)

class Solution {
public:
    pair<int, int> expandAroundCenter(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            --left;
            ++right;
        }
        return {left + 1, right - 1};
    }

    string longestPalindrome(string s) {
        int start = 0, end = 0;
        for (int i = 0; i < s.size(); ++i) {
            auto [left1, right1] = expandAroundCenter(s, i, i);
            auto [left2, right2] = expandAroundCenter(s, i, i + 1);
            if (right1 - left1 > end - start) {
                start = left1;
                end = right1;
            }
            if (right2 - left2 > end - start) {
                start = left2;
                end = right2;
            }
        }
        return s.substr(start, end - start + 1);
    }
};

遍历每一个点,左右扩展到最大,找到最大的回文。奇扩展,偶扩展各一遍。官方直接用left,right遍历。我自己写的就麻烦多了。

(2).动态规划O(n2)

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        string ans;
        for (int l = 0; l < n; ++l) {
            for (int i = 0; i + l < n; ++i) {
                int j = i + l;
                if (l == 0) {
                    dp[i][j] = 1;
                } else if (l == 1) {
                    dp[i][j] = (s[i] == s[j]);
                } else {
                    dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);
                }
                if (dp[i][j] && l + 1 > ans.size()) {
                    ans = s.substr(i, l + 1);
                }
            }
        }
        return ans;
    }
};

动态规划只是改变了查找的时候的速率,用表格存下dp[i+1][j-1]是不是回文,是的话判断s[i]和s[j]是否相等。

(3).manacher算法O(n)(面试不要求)

这个算法看的我头大。

class Solution {
public:
    int expand(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            --left;
            ++right;
        }
        return (right - left - 2) / 2;
    }

    string longestPalindrome(string s) {
        int start = 0, end = -1;
        string t = "#";
        for (char c: s) {
            t += c;
            t += '#';
        }
        t += '#';
        s = t;

        vector<int> arm_len;
        int right = -1, j = -1;
        for (int i = 0; i < s.size(); ++i) {
            int cur_arm_len;
            if (right >= i) {
                int i_sym = j * 2 - i;
                int min_arm_len = min(arm_len[i_sym], right - i);
                cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);
            } else {
                cur_arm_len = expand(s, i, i);
            }
            arm_len.push_back(cur_arm_len);
            if (i + cur_arm_len > right) {
                j = i;
                right = i + cur_arm_len;
            }
            if (cur_arm_len * 2 + 1 > end - start) {
                start = i - cur_arm_len;
                end = i + cur_arm_len;
            }
        }

        string ans;
        for (int i = start; i <= end; ++i) {
            if (s[i] != '#') {
                ans += s[i];
            }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值