leetcode
leetcode 2951 ~ 3000
分割回文串 II

分割回文串 II

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 152 ms, 内存: 16.0 MB


/*
 思路:
 1. Java Stream 不适合用于复杂的动态规划问题,但可以简化某些操作。
 2. 仍然使用动态规划方法解决,但用 Streams 优化部分代码。
*/

import java.util.stream.IntStream;

public class Solution {
    public int minCut(String s) {
        int n = s.length();
        boolean[][] isPalindrome = new boolean[n][n];
        int[] dp = IntStream.range(0, n).toArray(); // Initialize dp array
        IntStream.range(0, n).forEach(end -> {
            IntStream.rangeClosed(0, end).forEach(start -> {
                if (s.charAt(start) == s.charAt(end) && (end - start <= 2 || isPalindrome[start + 1][end - 1])) {
                    isPalindrome[start][end] = true;
                    if (start == 0) {
                        dp[end] = 0;
                    } else {
                        dp[end] = Math.min(dp[end], dp[start - 1] + 1);
                    }
                }
            });
        });
        return dp[n - 1];
    }
}

解释

方法:

本题解利用动态规划来计算分割字符串s成回文子串所需的最少分割次数。使用一个列表results,其中results[i]代表字符串s的前i个字符组成的子串分割成回文子串所需的最小次数。初始化results[i] = i - 1,意味着最坏情况下(即每个字符都需要分割),分割次数是i-1。接着,利用两个嵌套循环分别以每个字符为中心扩展寻找回文串。第一个循环寻找以s[i]为中心的奇数长度的回文子串,第二个循环寻找偶数长度的回文子串。若找到回文,则更新results[e+1](e为回文串的终点),使其为results[b] + 1的最小值,这里b是回文串的起点。这样,通过更新results数组,最终results[len(s)]即为将整个字符串s分割成回文子串所需的最少次数。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在动态规划解法中,初始化`results[i] = i - 1`的原因是什么?为什么不是其他值?
在动态规划中,`results[i] = i - 1`的初始化反映了字符串s的前i个字符在最坏情况下的分割次数。这是基于每个字符都独立成为一个回文子串的假设,即每个字符之间都需要一个分割。例如,对于字符串`abc`,最坏情况下需要分割成`a|b|c`,这需要两次分割,所以`results[3] = 2`。这种初始化确保了在动态规划过程中,我们总是从最大可能的分割次数开始优化,逐步寻找减少分割次数的可能,直到找到最小的分割次数。其他的初始化值要么不能覆盖所有情况,要么不符合问题的最坏情况设定。
🦆
对于找到的每个回文子串,更新`results[e+1]`时使用的`min`函数考虑了哪些可能的情况?如何确保这种方法不会遗漏更优的分割方案?
当找到一个回文子串`s[b:e+1]`时,`results[e+1]`的更新操作用`min`函数来确保我们记录到目前为止找到的以`e+1`为结束点的子串的最小分割次数。这里,`results[e+1] = min(results[e+1], results[b] + 1)`比较了当前记录的`results[e+1]`和新发现的回文子串的分割次数(即`results[b] + 1`,这里+1代表从b到e的这一段)。这种方法确保了每次都是取最小值,因此可以覆盖所有可能的分割方案,不会遗漏更优的分割。这是因为动态规划算法本质上是在考虑所有可能的分割方式,并实时更新到达每个位置的最小分割数。
🦆
为什么在判断回文串时,只需要检查字符`s[b]`与`s[e]`是否相等即可断定中间的字符串是回文?是否有可能出现中间部分不是回文的情况?
在这种特定的扩展中心方法中,我们是从中心向两边扩展来检查回文。在每次扩展时,我们只需检查`s[b]`与`s[e]`是否相等。如果相等,并且由于我们是从中心向外扩展,那么内部的字符串已经在之前的扩展中被验证为回文。例如,如果`s[b+1]`到`s[e-1]`是回文,并且`s[b]`等于`s[e]`,则`s[b]`到`s[e]`也必然是回文。这种方法确保了我们不会遇到中间部分不是回文的情况,因为我们是逐步验证每一个子回文串的。

相关问题