Skip to content

Commit 34cff77

Browse files
authored
feat: add solutions to lc/lcof2 problems: Palindrome Partitioning II (#1482)
* lc No.0132 & lcof2 No.084.Palindrome Partitioning II
1 parent bac0383 commit 34cff77

File tree

15 files changed

+588
-622
lines changed

15 files changed

+588
-622
lines changed

lcof2/剑指 Offer II 094. 最少回文分割/README.md

+134-57
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,21 @@
5353

5454
<!-- 这里可写通用的实现逻辑 -->
5555

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$ 的长度。
5771

5872
<!-- tabs:start -->
5973

@@ -65,18 +79,16 @@
6579
class Solution:
6680
def minCut(self, s: str) -> int:
6781
n = len(s)
68-
dp1 = [[False] * n for _ in range(n)]
82+
g = [[True] * n for _ in range(n)]
6983
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]
8092
```
8193

8294
### **Java**
@@ -87,54 +99,90 @@ class Solution:
8799
class Solution {
88100
public int minCut(String s) {
89101
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];
94109
}
95110
}
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);
104119
}
105120
}
106121
}
107-
return dp2[n - 1];
122+
return f[n - 1];
108123
}
109124
}
110125
```
111126

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+
112155
### **Go**
113156
114157
```go
115158
func minCut(s string) int {
116159
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+
}
120168
}
121169
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]
124172
}
125173
}
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)
133181
}
134182
}
135183
}
136184
}
137-
return dp2[n-1]
185+
return f[n-1]
138186
}
139187
140188
func min(x, y int) int {
@@ -145,33 +193,62 @@ func min(x, y int) int {
145193
}
146194
```
147195

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+
```
149222

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+
}
156237
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];
159240
}
160241
}
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);
169246
}
170247
}
171248
}
172-
return dp2[n - 1];
249+
return f[n - 1];
173250
}
174-
};
251+
}
175252
```
176253

177254
### **...**
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
1-
class Solution {
2-
public:
3-
int minCut(string s) {
4-
int n = s.size();
5-
vector<vector<bool>> dp1(n, vector<bool>(n));
6-
for (int i = n - 1; i >= 0; --i) {
7-
for (int j = i; j < n; ++j) {
8-
dp1[i][j] = s[i] == s[j] && (j - i < 3 || dp1[i + 1][j - 1]);
9-
}
10-
}
11-
vector<int> dp2(n);
12-
for (int i = 0; i < n; ++i) {
13-
if (!dp1[0][i]) {
14-
dp2[i] = i;
15-
for (int j = 1; j <= i; ++j) {
16-
if (dp1[j][i]) {
17-
dp2[i] = min(dp2[i], dp2[j - 1] + 1);
18-
}
19-
}
20-
}
21-
}
22-
return dp2[n - 1];
23-
}
24-
};
1+
class Solution {
2+
public:
3+
int minCut(string s) {
4+
int n = s.size();
5+
bool g[n][n];
6+
memset(g, true, sizeof(g));
7+
for (int i = n - 1; ~i; --i) {
8+
for (int j = i + 1; j < n; ++j) {
9+
g[i][j] = s[i] == s[j] && g[i + 1][j - 1];
10+
}
11+
}
12+
int f[n];
13+
iota(f, f + n, 0);
14+
for (int i = 1; i < n; ++i) {
15+
for (int j = 0; j <= i; ++j) {
16+
if (g[j][i]) {
17+
f[i] = min(f[i], j ? 1 + f[j - 1] : 0);
18+
}
19+
}
20+
}
21+
return f[n - 1];
22+
}
23+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
public class Solution {
2+
public int MinCut(string s) {
3+
int n = s.Length;
4+
bool[,] g = new bool[n,n];
5+
int[] f = new int[n];
6+
for (int i = 0; i < n; ++i) {
7+
f[i] = i;
8+
for (int j = 0; j < n; ++j) {
9+
g[i,j] = true;
10+
}
11+
}
12+
for (int i = n - 1; i >= 0; --i) {
13+
for (int j = i + 1; j < n; ++j) {
14+
g[i,j] = s[i] == s[j] && g[i + 1,j - 1];
15+
}
16+
}
17+
for (int i = 1; i < n; ++i) {
18+
for (int j = 0; j <= i; ++j) {
19+
if (g[j,i]) {
20+
f[i] = Math.Min(f[i], j > 0 ? 1 + f[j - 1] : 0);
21+
}
22+
}
23+
}
24+
return f[n - 1];
25+
}
26+
}

lcof2/剑指 Offer II 094. 最少回文分割/Solution.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,31 @@
11
func minCut(s string) int {
22
n := len(s)
3-
dp1 := make([][]bool, n)
4-
for i := 0; i < n; i++ {
5-
dp1[i] = make([]bool, n)
3+
g := make([][]bool, n)
4+
f := make([]int, n)
5+
for i := range g {
6+
g[i] = make([]bool, n)
7+
f[i] = i
8+
for j := range g[i] {
9+
g[i][j] = true
10+
}
611
}
712
for i := n - 1; i >= 0; i-- {
8-
for j := i; j < n; j++ {
9-
dp1[i][j] = s[i] == s[j] && (j-i < 3 || dp1[i+1][j-1])
13+
for j := i + 1; j < n; j++ {
14+
g[i][j] = s[i] == s[j] && g[i+1][j-1]
1015
}
1116
}
12-
dp2 := make([]int, n)
13-
for i := 0; i < n; i++ {
14-
if !dp1[0][i] {
15-
dp2[i] = i
16-
for j := 1; j <= i; j++ {
17-
if dp1[j][i] {
18-
dp2[i] = min(dp2[i], dp2[j-1]+1)
17+
for i := 1; i < n; i++ {
18+
for j := 0; j <= i; j++ {
19+
if g[j][i] {
20+
if j == 0 {
21+
f[i] = 0
22+
} else {
23+
f[i] = min(f[i], f[j-1]+1)
1924
}
2025
}
2126
}
2227
}
23-
return dp2[n-1]
28+
return f[n-1]
2429
}
2530

2631
func min(x, y int) int {

0 commit comments

Comments
 (0)