最长回文子串

本文介绍了三种不同的算法来寻找给定字符串中的最长回文子串:暴力法、动态规划和中心扩展法。暴力法通过穷举所有可能的子串并检查其是否为回文;动态规划利用状态转移方程减少重复计算;中心扩展法则围绕潜在的回文中心扩展以确定回文子串。
摘要由CSDN通过智能技术生成

力扣地址

暴力:(力扣过不了)

直接两层 for 循环遍历穷举所有区间,判断所有区间是否是回文

用了两种暴力法:

第一种、通过左右指针判断是否相等,不相等就返回false

第二种、通过字符串反转,因为回文的特性,左右、反转都相等

需要注意的边界问题:

1、是当字符串小于 2 时就是回文了,直接返回

2、大于 2 时,最小的回文长度是 1

3、字串的长度是 j - i + 1

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.size();
        if (len < 2) return s;
        int index = 0;
        int maxLen = 1;
        for (int i = 0; i < len - 1; ++i) {
            for (int j = i + 1; j < len; ++j) {
                // std::string tmp = s.substr(i, j - i + 1);
                // std::reverse(tmp.begin(), tmp.end());
                // if (s.substr(i, j - i + 1) == tmp) {
                if (judgePalindrome(s, i, j)) {
                    int tmp_len = j - i + 1;
                    if (tmp_len > maxLen) {
                        maxLen = tmp_len;
                        index = i;
                    }
                }
            }
        }
        return s.substr(index, maxLen);
    }

    bool judgePalindrome(string s, int left, int right) {
        while (left < right) {
            if (s[left++] != s[right--]) {
                return false;
            }
        }
        return true;
    }
};

时间复杂度O\left ( n^{3} \right ),显而易见,三个循环

空间复杂度O\left ( 1 \right ),常量个变量

 

动态规划:(对暴力求解进行优化)

因为暴力求解的过程中其实有大量的重复验证的工作,当验证 i 到 j 这一段字符串是否是回文时,如果我们提前验证了 i + 1 到 j - 1 这一段,

并且是回文串,那么我们只需要判断 s[i] 和 s[j] 就可以了知道 i 到 j 这一段是不是回文串了,这其实是一个状态转移的过程。

状态转移方程:

dp[i][j] = dp[i + 1][j - 1] \cup (s[i] == s[j])

对于长度小于 3 的字符串,我们需要特殊处理,因为长度为 1 就是回文,长度为 2 只需要比较 s[i] 和 s[j],不需要状态转移

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if (len < 2) return s;

        int index = 0;
        int max_len = 1;
        vector<vector<bool>> dp(len, vector<bool>(len, false));

        for (int l = 0; l < len; ++l) {
            for (int i = 0; i < len - l; ++i) {
                int j = i + l;
                if (0 == l) {
                    dp[i][j] = true;
                }
                else if (1 == l) {
                    dp[i][j] = (s[i] == s[j]);
                }
                else {
                    dp[i][j] = dp[i + 1][j - 1] && (s[i] == s[j]);
                }
                if (dp[i][j] && j - i + 1 > max_len) {
                    max_len = j - i + 1;
                    index = i;
                }
            }
        }
        return s.substr(index, max_len);
    }
};

代码中,第一个 for 循环 l 表示回文串的长度,从 0 开始,依次到最大长度减二,这里用 l == 0 表示长度为 1,l == 1 表示长度为 2,这里的 l 可以理解为 i 和 j 的间距,0 个间距自然只有一个字符,一个间距就有两个字符

时间复杂度O\left ( n^{2} \right ),显而易见,两个循环

空间复杂度O\left ( n^{2} \right ),用到了 dp,这是以空间换时间的算法

 

中心扩展算法

 

马拉车算法(Manacher

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值