leetcode
leetcode 1551 ~ 1600
由子序列构造的最长回文串的长度

由子序列构造的最长回文串的长度

难度:

标签:

题目描述

代码结果

运行时间: 868 ms, 内存: 16.7 MB


/*
题目思路:
1. 通过使用 Java Stream API 来实现与 Java 方法相同的逻辑。
2. 需要构造 dp 数组来存储动态规划过程中的结果。
*/
public class Solution {
    public int longestPalindrome(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        String s = word1 + word2;
        int len = s.length();
        int[][] dp = new int[len][len];
        int maxLen = 0;

        // 初始化 dp 数组
        IntStream.range(0, len).forEach(i -> dp[i][i] = 1);

        // 动态规划求解最长回文子序列长度
        IntStream.range(2, len + 1).forEach(l -> {
            IntStream.range(0, len - l + 1).forEach(i -> {
                int j = i + l - 1;
                if (s.charAt(i) == s.charAt(j)) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                    if (i < n && j >= n) {
                        maxLen = Math.max(maxLen, dp[i][j]);
                    }
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
            });
        });
        return maxLen;
    }
}

解释

方法:

这个题解使用动态规划来寻找连接后的字符串中最长的回文子序列的长度。首先,将两个字符串word1和word2连接成一个新字符串w。然后利用一个二维动态规划的技巧,但只使用一维数组dp来减少空间复杂度。遍历这个合并后的字符串,利用两层循环,外层从后向前,内层从外层的当前索引向后,来更新dp数组。若字符w[i]和w[j]相同,则dp[j]被更新为dp[j-1]加2;否则,dp[j]为dp[j]和dp[j-1]的最大值。特别地,如果i属于word1的部分,而j属于word2的部分,且形成了新的回文字符串,则更新最大长度res。最后,返回res。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
如何确保连接的子序列最终形成的字符串中包含的回文串是最长的,而不仅仅是任意回文串?
算法通过维护一个动态更新的dp数组来确保每次比较都取最长可能的回文长度。每次对于字符w[i]和w[j]相等的情况,dp[j]会被更新为dp[j-1]加2,这种方法是基于回文串的对称性质,并且通过不断比较和取较大值来确保任何时刻dp[j]存储的都是到目前为止最长的回文子序列长度。因此,通过这种方式,我们能够确保找到的是最长的回文子序列,而不是任意一个回文子序列。
🦆
在动态规划中,当w[i] != w[j]时,dp[j]取dp[j]与newDp[j-1]中的较大值。这种方法为何能确保跟踪到最长的回文长度?
当w[i] != w[j]时,说明当前的i和j位置的字符不能形成回文对,因此需要考虑不包含w[i]或w[j]的子序列。dp[j]代表了包含w[j]但不包含w[i]的最长回文序列长度,而newDp[j-1]代表了包含w[i]但不包含w[j]的最长回文序列长度。通过取这两者的最大值,算法能够确保至少一个字符(w[i]或w[j])被排除在外时,仍然能够追踪到目前为止的最长回文序列。这样的更新策略确保了在每一步都不丢失可能的最长回文长度。
🦆
为什么在初始化newDp数组时,设置newDp[i] = 1,这代表了什么?
在初始化newDp数组时,设置newDp[i] = 1是因为任何单个字符本身就是一个长度为1的回文串。这种初始化是基于回文串定义的基本性质 —— 单个字符总是对称的,因此总是一个回文。设置newDp[i] = 1提供了动态规划过程中的基础情况,即每个字符被视为最短的回文子序列。
🦆
题解中提到,只有当i属于word1且j属于word2时,才更新最大长度res。为什么这样的条件是必要的?
题解中的这个条件是为了确保计算的回文长度是由两个不同的输入字符串word1和word2的字符组成的。这一条件确保了回文串跨越了这两个字符串的边界,使得这个回文串确实是连接后字符串的子序列,并且利用了两个字符串的元素。如果没有这个条件,算法可能会错误地计算只来自word1或只来自word2的回文长度,而忽略了题目要求的通过连接两个字符串构造回文的目的。

相关问题