LeetCode:最长回文子串(动态规划)

一、题目

在这里插入图片描述
https://leetcode.cn/problems/longest-palindromic-substring/description/

二、 算法思想

使用动态规划思想解决,如果一个子串是回文的,并且它的左右两边各加上一个字符后仍然是回文的,那么这个子串加上这两个字符后也一定是回文的。因此可以用一个二维数组记录每个子串是否是回文的,然后逐步扩展子串的长度,直到找到最长的回文子串。

假设要判断 s[i…j] 是否是回文的,那么只需要判断 s[i+1…j-1] 是否是回文的,并且 s[i] == s[j],即可判断 s[i…j] 是否是回文的。因此可以用一个二维数组 dp[i][j] 表示 s[i…j] 是否是回文的,如果是回文的,dp[i][j] 的值为 true,否则为 false。初始化时,单个字符肯定是回文的,因此 dp[i][i] 的值都为 true。

然后逐步扩展子串的长度,如果 s[i+1…j-1] 是回文的,并且 s[i] == s[j],那么 s[i…j] 也是回文的,即 dp[i][j] = true。最后找到所有 dp[i][j] 为 true 的子串中长度最长的即可。

C++代码中,使用一个二维数组dp来存储每个子串是否为回文串的状态,其中dp[i][j]表示字符串s从下标i到下标j的子串是否为回文串。初始化时,所有状态都为0。
接下来,枚举所有可能的子串,从长度为1到n,依次计算每个子串是否为回文串,更新dp数组和最长回文子串的长度和起始位置。最后返回最长回文子串即可。

Java 代码实现

class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        String res = "";

        for (int len = 1; len <= n; len++) {    //len是回文子串长度
            for (int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;    //回文子串的右边界
                if (len == 1) {         // 单个字符是回文串
                    dp[i][j] = true;
                } else if (len == 2) {      // 两个字符相等就是回文串
                    dp[i][j] = s.charAt(i) == s.charAt(j);
                } else {        // 状态转移方程
                    dp[i][j] = dp[i+1][j-1] && s.charAt(i) == s.charAt(j);
                }

                if (dp[i][j] && len > res.length()) {   // 更新最长回文子串
                    res = s.substring(i, j+1);
                }
            }
        }
        return res;
    }
}

C++代码实现

class Solution {
public:
string longestPalindrome(string s) {
        int n = s.size();
        //创建一个n*n的二维矩阵(即一个二维向量),其中每个元素是一个整数。
        vector<vector<int>> dp(n, vector<int>(n)); // 初始化为0

        int start = 0, maxLen = 1;
        // 枚举所有可能的子串,从长度为1到n
        for (int len = 1; len <= n; ++len) {
            for (int i = 0; i + len - 1 < n; ++i) {
                int j = i + len - 1; // 子串右端点
                if (len == 1) {
                    dp[i][j] = 1; // 单个字符是回文串
                } else if (len == 2) {
                    dp[i][j] = (s[i] == s[j]); // 两个字符相等就是回文串
                } else {
                    dp[i][j] = (s[i] == s[j] && dp[i+1][j-1]); // 状态转移方程
                }

                if (dp[i][j] && len > maxLen) { // 更新最长回文子串的长度和起始位置
                    start = i;
                    maxLen = len;
                }
            }
        }
        return s.substr(start, maxLen); // 返回最长回文子串
    }
};

三、算法时间空间复杂度分析

Java代码

算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中 n n n 是字符串的长度。这是因为算法中使用了一个二维数组 d p dp dp,该数组的大小为 n × n n \times n n×n,且算法需要填充该数组的所有元素。对于每个元素 ( i , j ) (i,j) (i,j),需要使用 O ( 1 ) O(1) O(1) 的时间计算其值。

算法的空间复杂度也是 O ( n 2 ) O(n^2) O(n2)。这是因为算法中使用了一个二维数组 d p dp dp,该数组的大小为 n × n n \times n n×n。除此之外,算法还使用了一个字符串变量 r e s res res,其长度不超过 n n n。因此,该算法的总空间复杂度为 O ( n 2 ) O(n^2) O(n2)

C++代码

算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度也为 O ( n 2 ) O(n^2) O(n2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值