【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 ] dp[i] dp[i]代表使得子字符串 0... i 0...i 0...i為回文字符串組合的最小分割次數,那么 d p [ l e n ( s ) ? 1 ] dp[len(s) - 1] dp[len(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 ) dp[i] = min(dp[j] + 1) dp[i]=min(dp[j]+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 ] isOk[i][j] isOk[i][j]表示子字符串 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 ] s[i] == s[j] \text{ AND }isOk[i + 1][j - 1] s[i]==s[j]?AND?isOk[i+1][j?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++
/** @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
'''
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] = 0continuefor j in range(i):if isOk[j + 1][i]:dp[i] = min(dp[i], dp[j] + 1)return dp[-1]
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
/** @Author: LetMeFly* @Date: 2025-03-02 12:39:13* @LastEditors: LetMeFly.xyz* @LastEditTime: 2025-03-02 12:43:12*/
package mainfunc 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] = 0continue}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和我的個人博客,原創不易,轉載經作者同意后請附上原文鏈接哦~
千篇源碼題解已開源