53
53
54
54
<!-- 这里可写通用的实现逻辑 -->
55
55
56
- 两次 dp,` dp1[i][j] ` 表示 i ~ j 的子串是否是回文,可以参考 [ 5. 最长回文子串] ( ../../solution/0000-0099/0005.Longest%20Palindromic%20Substring/README.md ) 。` dp2[i] ` 表示以 i 结尾的子串最少需要分割几次,如果本来就是回文串(` dp[0][i] == true ` )就不需要分割,否则枚举分割点 ` j `
56
+ ** 方法一:动态规划**
57
+
58
+ 我们先预处理得到字符串 $s$ 的每一个子串 $s[ i..j] $ 是否为回文串,记录在二维数组 $g[ i] [ j ] $ 中,其中 $g[ i] [ j ] $ 表示子串 $s[ i..j] $ 是否为回文串。
59
+
60
+ 接下来,我们定义 $f[ i] $ 表示字符串 $s[ 0..i-1] $ 的最少分割次数,初始时 $f[ i] =i$。
61
+
62
+ 接下来,我们考虑 $f[ i] $ 如何进行状态转移。我们可以枚举上一个分割点 $j$,如果子串 $s[ j..i] $ 是一个回文串,那么 $f[ i] $ 就可以从 $f[ j] $ 转移而来。如果 $j=0$,那么说明 $s[ 0..i] $ 本身就是一个回文串,此时不需要进行分割,即 $f[ i] =0$。因此,状态转移方程如下:
63
+
64
+ $$
65
+ f[i]=\min_{0\leq j \leq i}\begin{cases} f[j-1]+1, & \text{if}\ g[j][i]=\text{True} \\ 0, & \text{if}\ g[0][i]=\text{True} \end{cases}
66
+ $$
67
+
68
+ 答案即为 $f[ n] $,其中 $n$ 是字符串 $s$ 的长度。
69
+
70
+ 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是字符串 $s$ 的长度。
57
71
58
72
<!-- tabs:start -->
59
73
65
79
class Solution :
66
80
def minCut (self , s : str ) -> int :
67
81
n = len (s)
68
- dp1 = [[False ] * n for _ in range (n)]
82
+ g = [[True ] * n for _ in range (n)]
69
83
for i in range (n - 1 , - 1 , - 1 ):
70
- for j in range (i, n):
71
- dp1[i][j] = s[i] == s[j] and (j - i < 3 or dp1[i + 1 ][j - 1 ])
72
- dp2 = [0 ] * n
73
- for i in range (n):
74
- if not dp1[0 ][i]:
75
- dp2[i] = i
76
- for j in range (1 , i + 1 ):
77
- if dp1[j][i]:
78
- dp2[i] = min (dp2[i], dp2[j - 1 ] + 1 )
79
- return dp2[- 1 ]
84
+ for j in range (i + 1 , n):
85
+ g[i][j] = s[i] == s[j] and g[i + 1 ][j - 1 ]
86
+ f = list (range (n))
87
+ for i in range (1 , n):
88
+ for j in range (i + 1 ):
89
+ if g[j][i]:
90
+ f[i] = min (f[i], 1 + f[j - 1 ] if j else 0 )
91
+ return f[- 1 ]
80
92
```
81
93
82
94
### ** Java**
@@ -87,54 +99,90 @@ class Solution:
87
99
class Solution {
88
100
public int minCut (String s ) {
89
101
int n = s. length();
90
- boolean [][] dp1 = new boolean [n][n];
91
- for (int i = n - 1 ; i >= 0 ; i-- ) {
92
- for (int j = i; j < n; j++ ) {
93
- dp1[i][j] = s. charAt(i) == s. charAt(j) && (j - i < 3 || dp1[i + 1 ][j - 1 ]);
102
+ boolean [][] g = new boolean [n][n];
103
+ for (var row : g) {
104
+ Arrays . fill(row, true );
105
+ }
106
+ for (int i = n - 1 ; i >= 0 ; -- i) {
107
+ for (int j = i + 1 ; j < n; ++ j) {
108
+ g[i][j] = s. charAt(i) == s. charAt(j) && g[i + 1 ][j - 1 ];
94
109
}
95
110
}
96
- int [] dp2 = new int [n];
97
- for (int i = 0 ; i < n; i ++ ) {
98
- if ( ! dp1[ 0 ][i]) {
99
- dp2[i] = i;
100
- for (int j = 1 ; j <= i; j ++ ) {
101
- if (dp1[j][i] ) {
102
- dp2[i] = Math . min(dp2 [i], dp2[j - 1 ] + 1 );
103
- }
111
+ int [] f = new int [n];
112
+ for (int i = 0 ; i < n; ++ i ) {
113
+ f[i] = i;
114
+ }
115
+ for (int i = 1 ; i < n; ++ i ) {
116
+ for ( int j = 0 ; j <= i; ++ j ) {
117
+ if (g[j] [i]) {
118
+ f[i] = Math . min(f[i], j > 0 ? 1 + f[j - 1 ] : 0 );
104
119
}
105
120
}
106
121
}
107
- return dp2 [n - 1 ];
122
+ return f [n - 1 ];
108
123
}
109
124
}
110
125
```
111
126
127
+ ### ** C++**
128
+
129
+ ``` cpp
130
+ class Solution {
131
+ public:
132
+ int minCut(string s) {
133
+ int n = s.size();
134
+ bool g[ n] [ n ] ;
135
+ memset(g, true, sizeof(g));
136
+ for (int i = n - 1; ~ i; --i) {
137
+ for (int j = i + 1; j < n; ++j) {
138
+ g[ i] [ j ] = s[ i] == s[ j] && g[ i + 1] [ j - 1 ] ;
139
+ }
140
+ }
141
+ int f[ n] ;
142
+ iota(f, f + n, 0);
143
+ for (int i = 1; i < n; ++i) {
144
+ for (int j = 0; j <= i; ++j) {
145
+ if (g[ j] [ i ] ) {
146
+ f[ i] = min(f[ i] , j ? 1 + f[ j - 1] : 0);
147
+ }
148
+ }
149
+ }
150
+ return f[ n - 1] ;
151
+ }
152
+ };
153
+ ```
154
+
112
155
### **Go**
113
156
114
157
```go
115
158
func minCut(s string) int {
116
159
n := len(s)
117
- dp1 := make ([][]bool , n)
118
- for i := 0 ; i < n; i++ {
119
- dp1[i] = make ([]bool , n)
160
+ g := make([][]bool, n)
161
+ f := make([]int, n)
162
+ for i := range g {
163
+ g[i] = make([]bool, n)
164
+ f[i] = i
165
+ for j := range g[i] {
166
+ g[i][j] = true
167
+ }
120
168
}
121
169
for i := n - 1; i >= 0; i-- {
122
- for j := i; j < n; j++ {
123
- dp1 [i][j] = s[i] == s[j] && (j-i < 3 || dp1 [i+1 ][j-1 ])
170
+ for j := i + 1 ; j < n; j++ {
171
+ g [i][j] = s[i] == s[j] && g [i+1][j-1]
124
172
}
125
173
}
126
- dp2 := make ([] int , n)
127
- for i := 0 ; i < n; i ++ {
128
- if !dp1[ 0 ][i] {
129
- dp2[i] = i
130
- for j := 1 ; j <= i; j++ {
131
- if dp1[j][i] {
132
- dp2 [i] = min (dp2 [i], dp2 [j-1 ]+1 )
174
+ for i := 1; i < n; i++ {
175
+ for j := 0; j <= i; j ++ {
176
+ if g[j ][i] {
177
+ if j == 0 {
178
+ f[i] = 0
179
+ } else {
180
+ f [i] = min(f [i], f [j-1]+1)
133
181
}
134
182
}
135
183
}
136
184
}
137
- return dp2 [n-1 ]
185
+ return f [n-1]
138
186
}
139
187
140
188
func min(x, y int) int {
@@ -145,33 +193,62 @@ func min(x, y int) int {
145
193
}
146
194
```
147
195
148
- ### ** C++**
196
+ ### ** TypeScript**
197
+
198
+ ``` ts
199
+ function minCut(s : string ): number {
200
+ const n = s .length ;
201
+ const g: boolean [][] = Array (n )
202
+ .fill (0 )
203
+ .map (() => Array (n ).fill (true ));
204
+ for (let i = n - 1 ; ~ i ; -- i ) {
205
+ for (let j = i + 1 ; j < n ; ++ j ) {
206
+ g [i ][j ] = s [i ] === s [j ] && g [i + 1 ][j - 1 ];
207
+ }
208
+ }
209
+ const f: number [] = Array (n )
210
+ .fill (0 )
211
+ .map ((_ , i ) => i );
212
+ for (let i = 1 ; i < n ; ++ i ) {
213
+ for (let j = 0 ; j <= i ; ++ j ) {
214
+ if (g [j ][i ]) {
215
+ f [i ] = Math .min (f [i ], j ? 1 + f [j - 1 ] : 0 );
216
+ }
217
+ }
218
+ }
219
+ return f [n - 1 ];
220
+ }
221
+ ```
149
222
150
- ``` cpp
151
- class Solution {
152
- public:
153
- int minCut(string s) {
154
- int n = s.size();
155
- vector<vector<bool >> dp1(n, vector<bool >(n));
223
+ ### ** C#**
224
+
225
+ ``` cs
226
+ public class Solution {
227
+ public int MinCut (string s ) {
228
+ int n = s .Length ;
229
+ bool [,] g = new bool [n ,n ];
230
+ int [] f = new int [n ];
231
+ for (int i = 0 ; i < n ; ++ i ) {
232
+ f [i ] = i ;
233
+ for (int j = 0 ; j < n ; ++ j ) {
234
+ g [i ,j ] = true ;
235
+ }
236
+ }
156
237
for (int i = n - 1 ; i >= 0 ; -- i ) {
157
- for (int j = i; j < n; ++j) {
158
- dp1 [ i ] [ j ] = s[ i] == s[ j] && (j - i < 3 || dp1 [ i + 1] [ j - 1 ] ) ;
238
+ for (int j = i + 1 ; j < n ; ++ j ) {
239
+ g [ i , j ] = s [i ] == s [j ] && g [i + 1 , j - 1 ];
159
240
}
160
241
}
161
- vector<int > dp2(n);
162
- for (int i = 0; i < n; ++i) {
163
- if (!dp1[ 0] [ i ] ) {
164
- dp2[ i] = i;
165
- for (int j = 1; j <= i; ++j) {
166
- if (dp1[ j] [ i ] ) {
167
- dp2[ i] = min(dp2[ i] , dp2[ j - 1] + 1);
168
- }
242
+ for (int i = 1 ; i < n ; ++ i ) {
243
+ for (int j = 0 ; j <= i ; ++ j ) {
244
+ if (g [j ,i ]) {
245
+ f [i ] = Math .Min (f [i ], j > 0 ? 1 + f [j - 1 ] : 0 );
169
246
}
170
247
}
171
248
}
172
- return dp2 [ n - 1] ;
249
+ return f [n - 1 ];
173
250
}
174
- };
251
+ }
175
252
```
176
253
177
254
### ** ...**
0 commit comments