CC19-分割回文串-ii
目录
一、题目描述
二、解题思路
三、代码实现
四、代码解释
五、复杂度分析
一、题目描述
给定一个字符串 s
,将其分割成若干子串,使得每个子串都是回文串。计算符合要求的最少分割次数。
示例:输入:"aab"
,返回值:1
(分割为 ["aa", "b"]
,只需分割 1 次)。
二、解题思路
采用动态规划的方法,分为两步:
- 预处理回文串:使用一个二维布尔数组
isPalindrome
记录区间[i, j]
内的子串是否为回文串。 - 计算最少分割次数:使用一维数组
dp
记录前i
个字符的最少分割次数,通过状态转移方程推导最优解。
三、代码实现
import java.util.*;public class Solution {public int minCut(String s) {int n = s.length();// 用于判断子串是否为回文boolean[][] isPalindrome = new boolean[n][n];for (int i = n - 1; i >= 0; i--) {for (int j = i; j < n; j++) {if (s.charAt(i) == s.charAt(j)) {if (j - i <= 1) {isPalindrome[i][j] = true;} else {isPalindrome[i][j] = isPalindrome[i + 1][j - 1];}}}}// dp[i] 表示前 i 个字符的最小切割数int[] dp = new int[n + 1];for (int i = 0; i <= n; i++) {dp[i] = i - 1;}for (int i = 1; i <= n; i++) {for (int j = 0; j < i; j++) {if (isPalindrome[j][i - 1]) {dp[i] = Math.min(dp[i], dp[j] + 1);}}}return dp[n];}// 测试方法public static void main(String[] args) {Solution solution = new Solution();String s = "aab";System.out.println("字符串 \"" + s + "\" 的最少分割次数:" + solution.minCut(s));}
}
四、代码解释
- 预处理回文串:
- 外层循环从后往前遍历
i
,内层循环从i
往后遍历j
。 - 若
s.charAt(i) == s.charAt(j)
,再判断子串长度:若长度小于等于 2(j - i <= 1
),则isPalindrome[i][j] = true
;否则,根据isPalindrome[i + 1][j - 1]
(子串[i+1, j-1]
是否为回文)来判断。
- 外层循环从后往前遍历
- 初始化
dp
数组:dp[i]
初始化为i - 1
,表示前i
个字符最多需要i - 1
次分割(每个字符单独成回文)。 - 状态转移:对于每个
i
(前i
个字符),遍历j
(从 0 到i - 1
),若[j, i - 1]
是回文串,则dp[i]
取dp[j] + 1
(前j
个字符的最少分割次数加 1)和当前dp[i]
的较小值。
五、复杂度分析
- 时间复杂度:
- 预处理回文串:两层循环,时间复杂度为 O(n2)。
- 计算最少分割次数:两层循环,时间复杂度为 O(n2)。
- 总的时间复杂度为 O(n2)。
- 空间复杂度:
- 二维数组
isPalindrome
:空间复杂度为 O(n2)。 - 一维数组
dp
:空间复杂度为 O(n)。 - 总的空间复杂度为 O(n2)。
- 二维数组