LeetCode 0132.分割回文串 II:动态规划

【LetMeFly】132.分割回文串 II:动态规划

力扣题目链接:https://leetcode.cn/problems/palindrome-partitioning-ii/

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。

返回符合要求的 最少分割次数

示例 1:

复制代码
输入:s = "aab"
输出:1
解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

示例 2:

复制代码
输入:s = "a"
输出:0

示例 3:

复制代码
输入:s = "ab"
输出:1

提示:

  • 1 <= s.length <= 2000
  • s 仅由小写英文字母组成

解题方法:动态规划

整个过程分为两步:预处理 和 动态规划

动态规划:

使用数组 d p dp dp,其中 d p i dpi dpi代表使得子字符串 0... i 0...i 0...i为回文字符串组合的最小分割次数,那么 d p l e n ( s ) − 1 dplen(s) - 1 dplen(s)−1即为答案。

  • 如果 0... i 0...i 0...i直接为回文字符串,那么分割次数为0。

  • 否则,对于 j ∈ 0... i − 1 j\in 0...i-1 j∈0...i−1,如果 j + 1.. i j + 1..i j+1..i是回文字符串,那么有 d p i = m i n ( d p j + 1 ) dpi = min(dpj + 1) dpi=min(dpj+1)

预处理:

有没有什么办法 O ( 1 ) O(1) O(1)时间内快速判断下标从 i i i到 j j j的子字符串是否为回文字符串?有,我们可以先使用 O ( n 2 ) O(n^2) O(n2)复杂度的时间预处理。使用 i s O k i j isOkij isOkij表示子字符串 i . . . j i...j i...j是否为回文字符串:

  • 如果子字符串为空或者长度为1,则是回文字符串( i ≥ j i \geq j i≥j)
  • 否则:是回文字符串当且仅当 s i = = s j AND i s O k i + 1 j − 1 si == sj \text{ AND }isOki + 1j - 1 si==sj AND isOki+1j−1

时空复杂度分析

  • 时间复杂度 O ( n 2 ) O(n^2) O(n2),预处理和动态规划的时间复杂度都是 O ( n 2 ) O(n^2) O(n2)。其中 n = l e n ( s ) n = len(s) n=len(s)
  • 空间复杂度 O ( n 2 ) O(n^2) O(n2)

AC代码

C++
cpp 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2025-03-02 12:02:45
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2025-03-02 12:26:06
 */
class Solution {
public:
    int minCut(string s) {
        vector<vector<bool>> isOk(s.size(), vector<bool>(s.size(), true));
        for (int i = s.size() - 1; i >= 0; i--) {
            for (int j = i + 1; j < s.size(); j++) {
                isOk[i][j] = s[i] == s[j] && isOk[i + 1][j - 1];
            }
        }

        vector<int> dp(s.size(), 1000000);
        for (int i = 0; i < s.size(); i++) {
            if (isOk[0][i]) {
                dp[i] = 0;
                continue;
            }
            for (int j = 0; j < i; j++) {
                if (isOk[j + 1][i]) {
                    dp[i] = min(dp[i], dp[j] + 1);
                }
            }
        }
        return dp.back();
    }
};
Python
python 复制代码
'''
Author: LetMeFly
Date: 2025-03-02 12:26:57
LastEditors: LetMeFly.xyz
LastEditTime: 2025-03-02 12:33:40
'''
class Solution:
    def minCut(self, s: str) -> int:
        isOk = [[True] * len(s) for _ in range(len(s))]
        for i in range(len(s) - 1, -1, -1):
            for j in range(i + 1, len(s)):
                isOk[i][j] = s[i] == s[j] and isOk[i + 1][j - 1]
        
        dp = [100000] * len(s)
        for i in range(len(s)):
            if isOk[0][i]:
                dp[i] = 0
                continue
            for j in range(i):
                if isOk[j + 1][i]:
                    dp[i] = min(dp[i], dp[j] + 1)
        return dp[-1]
Java
java 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2025-03-02 12:34:31
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2025-03-02 12:38:17
 */
class Solution {
    public int minCut(String s) {
        boolean[][] isOk = new boolean[s.length()][s.length()];
        for (int i = 0; i < s.length(); i++) {
            for (int j = 0; j < s.length(); j++) {
                isOk[i][j] = true;
            }
        }
        for (int i = s.length() - 1; i >= 0; i--) {
            for (int j = i + 1; j < s.length(); j++) {
                isOk[i][j] = s.charAt(i) == s.charAt(j) && isOk[i + 1][j - 1];
            }
        }

        int[] dp = new int[s.length()];
        for (int i = 0; i < s.length(); i++) {
            dp[i] = 100000;
        }
        for (int i = 0; i < s.length(); i++) {
            if (isOk[0][i]) {
                dp[i] = 0;
                continue;
            }
            for (int j = 0; j < i; j++) {
                if (isOk[j + 1][i]) {
                    dp[i] = Math.min(dp[i], dp[j] + 1);
                }
            }
        }
        return dp[dp.length - 1];
    }
}
Go
go 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2025-03-02 12:39:13
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2025-03-02 12:43:12
 */
package main

func minCut(s string) int {
    isOk := make([][]bool, len(s))
    for i, _ := range isOk {
        isOk[i] = make([]bool, len(s))
        for j, _ := range isOk[i] {
            isOk[i][j] = true
        }
    }
    for i := len(s) - 1; i >= 0; i-- {
        for j := i + 1; j < len(s); j++ {
            isOk[i][j] = s[i] == s[j] && isOk[i + 1][j - 1]
        }
    }

    dp := make([]int, len(s))
    for i, _ := range dp {
        dp[i] = 100000
    }
    for i := 0; i < len(dp); i++ {
        if isOk[0][i] {
            dp[i] = 0
            continue
        }
        for j := 0; j < i; j++ {
            if isOk[j + 1][i] {
                dp[i] = min(dp[i], dp[j] + 1)
            }
        }
    }
    return dp[len(dp) - 1]
}

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源

相关推荐
_日拱一卒5 小时前
LeetCode:207课程表
java·数据结构·算法·leetcode·职场和发展
风筝在晴天搁浅8 小时前
美团 LeetCode 692.前K个高频单词
算法·leetcode·职场和发展
z200509309 小时前
今日算法(回溯子集)(模版题)
数据结构·算法·leetcode
朔北之忘 Clancy10 小时前
2026 年 3 月青少年软编等考 C 语言二级真题解析
c语言·开发语言·c++·学习·青少年编程·题解·考级
YL2004042611 小时前
071字符串解码
数据结构·leetcode
z2005093013 小时前
今日算法(回溯子集)
数据结构·算法·leetcode
Hesionberger13 小时前
巧用异或找出唯一数字(多解)
java·数据结构·python·算法·leetcode
菜菜的顾清寒13 小时前
力扣HOT100(47) 二叉树的层序遍历
算法·leetcode·深度优先
sheeta199814 小时前
LeetCode 每日一题笔记 日期:2026.05.31 题目:2126. 摧毁小行星
笔记·算法·leetcode
INGNIGHT14 小时前
984.不含 AAA 或 BBB 的字符串(贪心)
开发语言·算法·leetcode