leetcode题解:第5题Longest Palindromic Substring

https://leetcode-cn.com/problems/longest-palindromic-substring/

解法一

采用动态规划的思路来优化暴力解法。
暴力解法自然是找出所有的子串然后判断是否是回文串,子串可以用其开头start和结尾end两个变量来表示。找到所有子串这个过程是没法优化的,因此我们要思考如何优化判断回文串这个过程。
对于dp[start][end],必须满足end >= start(首尾不能颠倒):

  1. 易知start == enddp[start][end] = true,即单个字符为回文串
  2. end == start + 1时,子串只有两个字符,是否为回文串就看这两个字符是否相等
  3. end > start + 1时,子串长度大于2,首先判断首尾两个字符是否相等,然后通过动态规划获取dp[start+1][end-1]的值,即除掉首尾后是否为回文串。若都满足则该子串为回文串。

需要注意,在采用动态规划时,要获取dp[start+1][end-1]的值,因此start要从大往小遍历,end要从小往大遍历,并且end >= start

代码
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.length();
        if (n == 0) return "";
        bool isPalin[n][n];
        string result(1, s[n - 1]);
        for (int start = n - 1; start >= 0; --start) {
            isPalin[start][start] = true;
            for (int end = start + 1; end < n; ++end) {
                isPalin[start][end] = s[start] == s[end];
                if (end > start + 1) isPalin[start][end] = isPalin[start][end] && isPalin[start + 1][end - 1];
                if (isPalin[start][end] && end - start + 1 > result.length()) 
                    result = s.substr(start, end - start + 1);
            }
        }
        return result;
    }
};
复杂度分析

算法要找到所有的start和end,这个过程时间复杂度 O ( n 2 ) O(n^2) O(n2),利用动态规划来判断s[start~end]是否为回文串,时间复杂度为 O ( 1 ) O(1) O(1),因此总的时间复杂度 O ( n 2 ) O(n^2) O(n2)。空间复杂度为 O ( n 2 ) O(n^2) O(n2)
需要注意,要用原生数组而不是vector来存储isPalin,因为vector的效率比原生数组要低很多,上述代码若改成vector则会超时。

解法二

中心扩散算法
考虑一个已经为回文串的子串,如果我们继续以它为中心去寻找回文串的话,自然是向左右两边扩散,如果两边字符相等则回文串增长,否则停止扩散。中心子串长度可能为1,也可能为2,需要全部考虑进去。
我们对所有可能的中心子串做中心扩散算法,找到以它们为中心的最长回文子串。

代码

class Solution {
public:
    string longestPalindrome(string s) {
        int start = 0, end = 0;
        for (int i = 0; i < s.length(); ++i) {
            auto [left1, right1] = expandStr(s, i, i);
            auto [left2, right2] = expandStr(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);
    }
private:
    pair<int, int> expandStr(string s, int left, int right) {
        while (left >= 0 && right < s.length() && s[left] == s[right]) {
            left--;
            right++;
        }
        return {left + 1, right - 1};
    }
};
复杂度分析

遍历中心子串复杂度 O ( n ) O(n) O(n),扩散算法复杂度 O ( n ) O(n) O(n),总的时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值