Skip to content

Commit ad0ff4f

Browse files
authored
feat: add solutions to lc problem: No.1745 (#4109)
No.1745.Palindrome Partitioning IV
1 parent 0a017c9 commit ad0ff4f

File tree

7 files changed

+156
-61
lines changed

7 files changed

+156
-61
lines changed

solution/1700-1799/1745.Palindrome Partitioning IV/README.md

+58-21
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,26 @@ tags:
5656

5757
<!-- solution:start -->
5858

59-
### 方法一:预处理 + 枚举
59+
### 方法一:动态规划
6060

61-
预处理出字符串 `s` 的所有子串是否为回文串,然后枚举 `s` 的所有分割点,判断是否满足条件
61+
我们定义 $f[i][j]$ 表示字符串 $s$ 的第 $i$ 个字符到第 $j$ 个字符是否为回文串,初始时 $f[i][j] = \textit{true}$
6262

63-
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 `s` 的长度。
63+
然后我们可以通过以下的状态转移方程来计算 $f[i][j]$:
64+
65+
$$
66+
f[i][j] = \begin{cases}
67+
\textit{true}, & \text{if } s[i] = s[j] \text{ and } (i + 1 = j \text{ or } f[i + 1][j - 1]) \\
68+
\textit{false}, & \text{otherwise}
69+
\end{cases}
70+
$$
71+
72+
由于 $f[i][j]$ 依赖于 $f[i + 1][j - 1]$,因此,我们需要从大到小的顺序枚举 $i$,从小到大的顺序枚举 $j$,这样才能保证当计算 $f[i][j]$ 时 $f[i + 1][j - 1]$ 已经被计算过。
73+
74+
接下来,我们枚举第一个子串的右端点 $i$,第二个子串的右端点 $j$,那么第三个子串的左端点可以枚举的范围为 $[j + 1, n - 1]$,其中 $n$ 是字符串 $s$ 的长度。如果第一个子串 $s[0..i]$、第二个子串 $s[i+1..j]$ 和第三个子串 $s[j+1..n-1]$ 都是回文串,那么我们就找到了一种可行的分割方案,返回 $\textit{true}$。
75+
76+
枚举完所有的分割方案后,如果没有找到符合要求的分割方案,那么返回 $\textit{false}$。
77+
78+
时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是字符串 $s$ 的长度。
6479

6580
<!-- tabs:start -->
6681

@@ -70,13 +85,13 @@ tags:
7085
class Solution:
7186
def checkPartitioning(self, s: str) -> bool:
7287
n = len(s)
73-
g = [[True] * n for _ in range(n)]
88+
f = [[True] * n for _ in range(n)]
7489
for i in range(n - 1, -1, -1):
7590
for j in range(i + 1, n):
76-
g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1])
91+
f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1])
7792
for i in range(n - 2):
7893
for j in range(i + 1, n - 1):
79-
if g[0][i] and g[i + 1][j] and g[j + 1][-1]:
94+
if f[0][i] and f[i + 1][j] and f[j + 1][-1]:
8095
return True
8196
return False
8297
```
@@ -87,18 +102,18 @@ class Solution:
87102
class Solution {
88103
public boolean checkPartitioning(String s) {
89104
int n = s.length();
90-
boolean[][] g = new boolean[n][n];
91-
for (var e : g) {
92-
Arrays.fill(e, true);
105+
boolean[][] f = new boolean[n][n];
106+
for (var g : f) {
107+
Arrays.fill(g, true);
93108
}
94109
for (int i = n - 1; i >= 0; --i) {
95110
for (int j = i + 1; j < n; ++j) {
96-
g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]);
111+
f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]);
97112
}
98113
}
99114
for (int i = 0; i < n - 2; ++i) {
100115
for (int j = i + 1; j < n - 1; ++j) {
101-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
116+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
102117
return true;
103118
}
104119
}
@@ -115,15 +130,15 @@ class Solution {
115130
public:
116131
bool checkPartitioning(string s) {
117132
int n = s.size();
118-
vector<vector<bool>> g(n, vector<bool>(n, true));
133+
vector<vector<bool>> f(n, vector<bool>(n, true));
119134
for (int i = n - 1; i >= 0; --i) {
120135
for (int j = i + 1; j < n; ++j) {
121-
g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]);
136+
f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]);
122137
}
123138
}
124139
for (int i = 0; i < n - 2; ++i) {
125140
for (int j = i + 1; j < n - 1; ++j) {
126-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
141+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
127142
return true;
128143
}
129144
}
@@ -138,21 +153,21 @@ public:
138153
```go
139154
func checkPartitioning(s string) bool {
140155
n := len(s)
141-
g := make([][]bool, n)
142-
for i := range g {
143-
g[i] = make([]bool, n)
144-
for j := range g[i] {
145-
g[i][j] = true
156+
f := make([][]bool, n)
157+
for i := range f {
158+
f[i] = make([]bool, n)
159+
for j := range f[i] {
160+
f[i][j] = true
146161
}
147162
}
148163
for i := n - 1; i >= 0; i-- {
149164
for j := i + 1; j < n; j++ {
150-
g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1])
165+
f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1])
151166
}
152167
}
153168
for i := 0; i < n-2; i++ {
154169
for j := i + 1; j < n-1; j++ {
155-
if g[0][i] && g[i+1][j] && g[j+1][n-1] {
170+
if f[0][i] && f[i+1][j] && f[j+1][n-1] {
156171
return true
157172
}
158173
}
@@ -161,6 +176,28 @@ func checkPartitioning(s string) bool {
161176
}
162177
```
163178

179+
#### TypeScript
180+
181+
```ts
182+
function checkPartitioning(s: string): boolean {
183+
const n = s.length;
184+
const f: boolean[][] = Array.from({ length: n }, () => Array(n).fill(true));
185+
for (let i = n - 1; i >= 0; --i) {
186+
for (let j = i + 1; j < n; ++j) {
187+
f[i][j] = s[i] === s[j] && f[i + 1][j - 1];
188+
}
189+
}
190+
for (let i = 0; i < n - 2; ++i) {
191+
for (let j = i + 1; j < n - 1; ++j) {
192+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
193+
return true;
194+
}
195+
}
196+
}
197+
return false;
198+
}
199+
```
200+
164201
<!-- tabs:end -->
165202

166203
<!-- solution:end -->

solution/1700-1799/1745.Palindrome Partitioning IV/README_EN.md

+60-19
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,26 @@ tags:
5454

5555
<!-- solution:start -->
5656

57-
### Solution 1
57+
### Solution 1: Dynamic Programming
58+
59+
We define $f[i][j]$ to indicate whether the substring of $s$ from the $i$-th character to the $j$-th character is a palindrome, initially $f[i][j] = \textit{true}$.
60+
61+
Then we can calculate $f[i][j]$ using the following state transition equation:
62+
63+
$$
64+
f[i][j] = \begin{cases}
65+
\textit{true}, & \text{if } s[i] = s[j] \text{ and } (i + 1 = j \text{ or } f[i + 1][j - 1]) \\
66+
\textit{false}, & \text{otherwise}
67+
\end{cases}
68+
$$
69+
70+
Since $f[i][j]$ depends on $f[i + 1][j - 1]$, we need to enumerate $i$ from large to small and $j$ from small to large, so that when calculating $f[i][j]$, $f[i + 1][j - 1]$ has already been calculated.
71+
72+
Next, we enumerate the right endpoint $i$ of the first substring and the right endpoint $j$ of the second substring. The left endpoint of the third substring can be enumerated in the range $[j + 1, n - 1]$, where $n$ is the length of the string $s$. If the first substring $s[0..i]$, the second substring $s[i+1..j]$, and the third substring $s[j+1..n-1]$ are all palindromes, then we have found a feasible partitioning scheme and return $\textit{true}$.
73+
74+
After enumerating all partitioning schemes, if no valid partitioning scheme is found, return $\textit{false}$.
75+
76+
Time complexity is $O(n^2)$, and space complexity is $O(n^2)$. Where $n$ is the length of the string $s$.
5877

5978
<!-- tabs:start -->
6079

@@ -64,13 +83,13 @@ tags:
6483
class Solution:
6584
def checkPartitioning(self, s: str) -> bool:
6685
n = len(s)
67-
g = [[True] * n for _ in range(n)]
86+
f = [[True] * n for _ in range(n)]
6887
for i in range(n - 1, -1, -1):
6988
for j in range(i + 1, n):
70-
g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1])
89+
f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1])
7190
for i in range(n - 2):
7291
for j in range(i + 1, n - 1):
73-
if g[0][i] and g[i + 1][j] and g[j + 1][-1]:
92+
if f[0][i] and f[i + 1][j] and f[j + 1][-1]:
7493
return True
7594
return False
7695
```
@@ -81,18 +100,18 @@ class Solution:
81100
class Solution {
82101
public boolean checkPartitioning(String s) {
83102
int n = s.length();
84-
boolean[][] g = new boolean[n][n];
85-
for (var e : g) {
86-
Arrays.fill(e, true);
103+
boolean[][] f = new boolean[n][n];
104+
for (var g : f) {
105+
Arrays.fill(g, true);
87106
}
88107
for (int i = n - 1; i >= 0; --i) {
89108
for (int j = i + 1; j < n; ++j) {
90-
g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]);
109+
f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]);
91110
}
92111
}
93112
for (int i = 0; i < n - 2; ++i) {
94113
for (int j = i + 1; j < n - 1; ++j) {
95-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
114+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
96115
return true;
97116
}
98117
}
@@ -109,15 +128,15 @@ class Solution {
109128
public:
110129
bool checkPartitioning(string s) {
111130
int n = s.size();
112-
vector<vector<bool>> g(n, vector<bool>(n, true));
131+
vector<vector<bool>> f(n, vector<bool>(n, true));
113132
for (int i = n - 1; i >= 0; --i) {
114133
for (int j = i + 1; j < n; ++j) {
115-
g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]);
134+
f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]);
116135
}
117136
}
118137
for (int i = 0; i < n - 2; ++i) {
119138
for (int j = i + 1; j < n - 1; ++j) {
120-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
139+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
121140
return true;
122141
}
123142
}
@@ -132,21 +151,21 @@ public:
132151
```go
133152
func checkPartitioning(s string) bool {
134153
n := len(s)
135-
g := make([][]bool, n)
136-
for i := range g {
137-
g[i] = make([]bool, n)
138-
for j := range g[i] {
139-
g[i][j] = true
154+
f := make([][]bool, n)
155+
for i := range f {
156+
f[i] = make([]bool, n)
157+
for j := range f[i] {
158+
f[i][j] = true
140159
}
141160
}
142161
for i := n - 1; i >= 0; i-- {
143162
for j := i + 1; j < n; j++ {
144-
g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1])
163+
f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1])
145164
}
146165
}
147166
for i := 0; i < n-2; i++ {
148167
for j := i + 1; j < n-1; j++ {
149-
if g[0][i] && g[i+1][j] && g[j+1][n-1] {
168+
if f[0][i] && f[i+1][j] && f[j+1][n-1] {
150169
return true
151170
}
152171
}
@@ -155,6 +174,28 @@ func checkPartitioning(s string) bool {
155174
}
156175
```
157176

177+
#### TypeScript
178+
179+
```ts
180+
function checkPartitioning(s: string): boolean {
181+
const n = s.length;
182+
const f: boolean[][] = Array.from({ length: n }, () => Array(n).fill(true));
183+
for (let i = n - 1; i >= 0; --i) {
184+
for (let j = i + 1; j < n; ++j) {
185+
f[i][j] = s[i] === s[j] && f[i + 1][j - 1];
186+
}
187+
}
188+
for (let i = 0; i < n - 2; ++i) {
189+
for (let j = i + 1; j < n - 1; ++j) {
190+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
191+
return true;
192+
}
193+
}
194+
}
195+
return false;
196+
}
197+
```
198+
158199
<!-- tabs:end -->
159200

160201
<!-- solution:end -->

solution/1700-1799/1745.Palindrome Partitioning IV/Solution.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ class Solution {
22
public:
33
bool checkPartitioning(string s) {
44
int n = s.size();
5-
vector<vector<bool>> g(n, vector<bool>(n, true));
5+
vector<vector<bool>> f(n, vector<bool>(n, true));
66
for (int i = n - 1; i >= 0; --i) {
77
for (int j = i + 1; j < n; ++j) {
8-
g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]);
8+
f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]);
99
}
1010
}
1111
for (int i = 0; i < n - 2; ++i) {
1212
for (int j = i + 1; j < n - 1; ++j) {
13-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
13+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
1414
return true;
1515
}
1616
}
1717
}
1818
return false;
1919
}
20-
};
20+
};
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
func checkPartitioning(s string) bool {
22
n := len(s)
3-
g := make([][]bool, n)
4-
for i := range g {
5-
g[i] = make([]bool, n)
6-
for j := range g[i] {
7-
g[i][j] = true
3+
f := make([][]bool, n)
4+
for i := range f {
5+
f[i] = make([]bool, n)
6+
for j := range f[i] {
7+
f[i][j] = true
88
}
99
}
1010
for i := n - 1; i >= 0; i-- {
1111
for j := i + 1; j < n; j++ {
12-
g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1])
12+
f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1])
1313
}
1414
}
1515
for i := 0; i < n-2; i++ {
1616
for j := i + 1; j < n-1; j++ {
17-
if g[0][i] && g[i+1][j] && g[j+1][n-1] {
17+
if f[0][i] && f[i+1][j] && f[j+1][n-1] {
1818
return true
1919
}
2020
}
2121
}
2222
return false
23-
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
class Solution {
22
public boolean checkPartitioning(String s) {
33
int n = s.length();
4-
boolean[][] g = new boolean[n][n];
5-
for (var e : g) {
6-
Arrays.fill(e, true);
4+
boolean[][] f = new boolean[n][n];
5+
for (var g : f) {
6+
Arrays.fill(g, true);
77
}
88
for (int i = n - 1; i >= 0; --i) {
99
for (int j = i + 1; j < n; ++j) {
10-
g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]);
10+
f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]);
1111
}
1212
}
1313
for (int i = 0; i < n - 2; ++i) {
1414
for (int j = i + 1; j < n - 1; ++j) {
15-
if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) {
15+
if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) {
1616
return true;
1717
}
1818
}
1919
}
2020
return false;
2121
}
22-
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
class Solution:
22
def checkPartitioning(self, s: str) -> bool:
33
n = len(s)
4-
g = [[True] * n for _ in range(n)]
4+
f = [[True] * n for _ in range(n)]
55
for i in range(n - 1, -1, -1):
66
for j in range(i + 1, n):
7-
g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1])
7+
f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1])
88
for i in range(n - 2):
99
for j in range(i + 1, n - 1):
10-
if g[0][i] and g[i + 1][j] and g[j + 1][-1]:
10+
if f[0][i] and f[i + 1][j] and f[j + 1][-1]:
1111
return True
1212
return False

0 commit comments

Comments
 (0)