Skip to content

Commit 2bbd0ff

Browse files
authored
feat: add solutions to lc problem: No.3472 (#4125)
No.3472.Longest Palindromic Subsequence After at Most K Operations
1 parent 4db4256 commit 2bbd0ff

File tree

7 files changed

+480
-8
lines changed

7 files changed

+480
-8
lines changed

solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README.md

+166-4
Original file line numberDiff line numberDiff line change
@@ -77,32 +77,194 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3400-3499/3472.Lo
7777

7878
<!-- solution:start -->
7979

80-
### 方法一
80+
### 方法一:记忆化搜索
81+
82+
我们设计一个函数 $\textit{dfs}(i, j, k)$,表示在字符串 $s[i..j]$ 中最多可以进行 $k$ 次操作,得到的最长回文子序列的长度。那么答案为 $\textit{dfs}(0, n - 1, k)$。
83+
84+
函数 $\textit{dfs}(i, j, k)$ 的计算过程如下:
85+
86+
- 如果 $i > j$,返回 $0$;
87+
- 如果 $i = j$,返回 $1$;
88+
- 否则,我们可以忽略 $s[i]$ 或 $s[j]$,分别计算 $\textit{dfs}(i + 1, j, k)$ 和 $\textit{dfs}(i, j - 1, k)$;或者我们可以将 $s[i]$ 和 $s[j]$ 变成相同的字符,计算 $\textit{dfs}(i + 1, j - 1, k - t) + 2$,其中 $t$ 是 $s[i]$ 和 $s[j]$ 的 ASCII 码差值。
89+
- 返回上述三种情况的最大值。
90+
91+
为了避免重复计算,我们使用记忆化搜索的方法。
92+
93+
时间复杂度 $O(n^2 \times k)$,空间复杂度 $O(n^2 \times k)$。其中 $n$ 是字符串 $s$ 的长度。
8194

8295
<!-- tabs:start -->
8396

8497
#### Python3
8598

8699
```python
87-
100+
class Solution:
101+
def longestPalindromicSubsequence(self, s: str, k: int) -> int:
102+
@cache
103+
def dfs(i: int, j: int, k: int) -> int:
104+
if i > j:
105+
return 0
106+
if i == j:
107+
return 1
108+
res = max(dfs(i + 1, j, k), dfs(i, j - 1, k))
109+
d = abs(s[i] - s[j])
110+
t = min(d, 26 - d)
111+
if t <= k:
112+
res = max(res, dfs(i + 1, j - 1, k - t) + 2)
113+
return res
114+
115+
s = list(map(ord, s))
116+
n = len(s)
117+
ans = dfs(0, n - 1, k)
118+
dfs.cache_clear()
119+
return ans
88120
```
89121

90122
#### Java
91123

92124
```java
93-
125+
class Solution {
126+
private char[] s;
127+
private Integer[][][] f;
128+
129+
public int longestPalindromicSubsequence(String s, int k) {
130+
this.s = s.toCharArray();
131+
int n = s.length();
132+
f = new Integer[n][n][k + 1];
133+
return dfs(0, n - 1, k);
134+
}
135+
136+
private int dfs(int i, int j, int k) {
137+
if (i > j) {
138+
return 0;
139+
}
140+
if (i == j) {
141+
return 1;
142+
}
143+
if (f[i][j][k] != null) {
144+
return f[i][j][k];
145+
}
146+
int res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k));
147+
int d = Math.abs(s[i] - s[j]);
148+
int t = Math.min(d, 26 - d);
149+
if (t <= k) {
150+
res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t));
151+
}
152+
f[i][j][k] = res;
153+
return res;
154+
}
155+
}
94156
```
95157

96158
#### C++
97159

98160
```cpp
99-
161+
class Solution {
162+
public:
163+
int longestPalindromicSubsequence(string s, int k) {
164+
int n = s.size();
165+
vector f(n, vector(n, vector<int>(k + 1, -1)));
166+
auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int {
167+
if (i > j) {
168+
return 0;
169+
}
170+
if (i == j) {
171+
return 1;
172+
}
173+
if (f[i][j][k] != -1) {
174+
return f[i][j][k];
175+
}
176+
int res = max(dfs(i + 1, j, k), dfs(i, j - 1, k));
177+
int d = abs(s[i] - s[j]);
178+
int t = min(d, 26 - d);
179+
if (t <= k) {
180+
res = max(res, 2 + dfs(i + 1, j - 1, k - t));
181+
}
182+
return f[i][j][k] = res;
183+
};
184+
return dfs(0, n - 1, k);
185+
}
186+
};
100187
```
101188
102189
#### Go
103190
104191
```go
192+
func longestPalindromicSubsequence(s string, k int) int {
193+
n := len(s)
194+
f := make([][][]int, n)
195+
for i := range f {
196+
f[i] = make([][]int, n)
197+
for j := range f[i] {
198+
f[i][j] = make([]int, k+1)
199+
for l := range f[i][j] {
200+
f[i][j][l] = -1
201+
}
202+
}
203+
}
204+
var dfs func(int, int, int) int
205+
dfs = func(i, j, k int) int {
206+
if i > j {
207+
return 0
208+
}
209+
if i == j {
210+
return 1
211+
}
212+
if f[i][j][k] != -1 {
213+
return f[i][j][k]
214+
}
215+
res := max(dfs(i+1, j, k), dfs(i, j-1, k))
216+
d := abs(int(s[i]) - int(s[j]))
217+
t := min(d, 26-d)
218+
if t <= k {
219+
res = max(res, 2+dfs(i+1, j-1, k-t))
220+
}
221+
f[i][j][k] = res
222+
return res
223+
}
224+
return dfs(0, n-1, k)
225+
}
226+
227+
func abs(x int) int {
228+
if x < 0 {
229+
return -x
230+
}
231+
return x
232+
}
233+
```
105234

235+
#### TypeScript
236+
237+
```ts
238+
function longestPalindromicSubsequence(s: string, k: number): number {
239+
const n = s.length;
240+
const sCodes = s.split('').map(c => c.charCodeAt(0));
241+
const f: number[][][] = Array.from({ length: n }, () =>
242+
Array.from({ length: n }, () => Array(k + 1).fill(-1)),
243+
);
244+
245+
function dfs(i: number, j: number, k: number): number {
246+
if (i > j) {
247+
return 0;
248+
}
249+
if (i === j) {
250+
return 1;
251+
}
252+
253+
if (f[i][j][k] !== -1) {
254+
return f[i][j][k];
255+
}
256+
257+
let res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k));
258+
const d = Math.abs(sCodes[i] - sCodes[j]);
259+
const t = Math.min(d, 26 - d);
260+
if (t <= k) {
261+
res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t));
262+
}
263+
return (f[i][j][k] = res);
264+
}
265+
266+
return dfs(0, n - 1, k);
267+
}
106268
```
107269

108270
<!-- tabs:end -->

solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README_EN.md

+166-4
Original file line numberDiff line numberDiff line change
@@ -71,32 +71,194 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3400-3499/3472.Lo
7171

7272
<!-- solution:start -->
7373

74-
### Solution 1
74+
### Solution 1: Memoized Search
75+
76+
We design a function $\textit{dfs}(i, j, k)$, which represents the length of the longest palindromic subsequence that can be obtained in the substring $s[i..j]$ with at most $k$ operations. The answer is $\textit{dfs}(0, n - 1, k)$.
77+
78+
The calculation process of the function $\textit{dfs}(i, j, k)$ is as follows:
79+
80+
- If $i > j$, return $0$;
81+
- If $i = j$, return $1$;
82+
- Otherwise, we can ignore $s[i]$ or $s[j]$ and calculate $\textit{dfs}(i + 1, j, k)$ and $\textit{dfs}(i, j - 1, k)$ respectively; or we can change $s[i]$ and $s[j]$ to the same character and calculate $\textit{dfs}(i + 1, j - 1, k - t) + 2$, where $t$ is the ASCII code difference between $s[i]$ and $s[j]$.
83+
- Return the maximum value of the above three cases.
84+
85+
To avoid repeated calculations, we use memoized search.
86+
87+
The time complexity is $O(n^2 \times k)$, and the space complexity is $O(n^2 \times k)$. Where $n$ is the length of the string $s$.
7588

7689
<!-- tabs:start -->
7790

7891
#### Python3
7992

8093
```python
81-
94+
class Solution:
95+
def longestPalindromicSubsequence(self, s: str, k: int) -> int:
96+
@cache
97+
def dfs(i: int, j: int, k: int) -> int:
98+
if i > j:
99+
return 0
100+
if i == j:
101+
return 1
102+
res = max(dfs(i + 1, j, k), dfs(i, j - 1, k))
103+
d = abs(s[i] - s[j])
104+
t = min(d, 26 - d)
105+
if t <= k:
106+
res = max(res, dfs(i + 1, j - 1, k - t) + 2)
107+
return res
108+
109+
s = list(map(ord, s))
110+
n = len(s)
111+
ans = dfs(0, n - 1, k)
112+
dfs.cache_clear()
113+
return ans
82114
```
83115

84116
#### Java
85117

86118
```java
87-
119+
class Solution {
120+
private char[] s;
121+
private Integer[][][] f;
122+
123+
public int longestPalindromicSubsequence(String s, int k) {
124+
this.s = s.toCharArray();
125+
int n = s.length();
126+
f = new Integer[n][n][k + 1];
127+
return dfs(0, n - 1, k);
128+
}
129+
130+
private int dfs(int i, int j, int k) {
131+
if (i > j) {
132+
return 0;
133+
}
134+
if (i == j) {
135+
return 1;
136+
}
137+
if (f[i][j][k] != null) {
138+
return f[i][j][k];
139+
}
140+
int res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k));
141+
int d = Math.abs(s[i] - s[j]);
142+
int t = Math.min(d, 26 - d);
143+
if (t <= k) {
144+
res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t));
145+
}
146+
f[i][j][k] = res;
147+
return res;
148+
}
149+
}
88150
```
89151

90152
#### C++
91153

92154
```cpp
93-
155+
class Solution {
156+
public:
157+
int longestPalindromicSubsequence(string s, int k) {
158+
int n = s.size();
159+
vector f(n, vector(n, vector<int>(k + 1, -1)));
160+
auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int {
161+
if (i > j) {
162+
return 0;
163+
}
164+
if (i == j) {
165+
return 1;
166+
}
167+
if (f[i][j][k] != -1) {
168+
return f[i][j][k];
169+
}
170+
int res = max(dfs(i + 1, j, k), dfs(i, j - 1, k));
171+
int d = abs(s[i] - s[j]);
172+
int t = min(d, 26 - d);
173+
if (t <= k) {
174+
res = max(res, 2 + dfs(i + 1, j - 1, k - t));
175+
}
176+
return f[i][j][k] = res;
177+
};
178+
return dfs(0, n - 1, k);
179+
}
180+
};
94181
```
95182
96183
#### Go
97184
98185
```go
186+
func longestPalindromicSubsequence(s string, k int) int {
187+
n := len(s)
188+
f := make([][][]int, n)
189+
for i := range f {
190+
f[i] = make([][]int, n)
191+
for j := range f[i] {
192+
f[i][j] = make([]int, k+1)
193+
for l := range f[i][j] {
194+
f[i][j][l] = -1
195+
}
196+
}
197+
}
198+
var dfs func(int, int, int) int
199+
dfs = func(i, j, k int) int {
200+
if i > j {
201+
return 0
202+
}
203+
if i == j {
204+
return 1
205+
}
206+
if f[i][j][k] != -1 {
207+
return f[i][j][k]
208+
}
209+
res := max(dfs(i+1, j, k), dfs(i, j-1, k))
210+
d := abs(int(s[i]) - int(s[j]))
211+
t := min(d, 26-d)
212+
if t <= k {
213+
res = max(res, 2+dfs(i+1, j-1, k-t))
214+
}
215+
f[i][j][k] = res
216+
return res
217+
}
218+
return dfs(0, n-1, k)
219+
}
220+
221+
func abs(x int) int {
222+
if x < 0 {
223+
return -x
224+
}
225+
return x
226+
}
227+
```
99228

229+
#### TypeScript
230+
231+
```ts
232+
function longestPalindromicSubsequence(s: string, k: number): number {
233+
const n = s.length;
234+
const sCodes = s.split('').map(c => c.charCodeAt(0));
235+
const f: number[][][] = Array.from({ length: n }, () =>
236+
Array.from({ length: n }, () => Array(k + 1).fill(-1)),
237+
);
238+
239+
function dfs(i: number, j: number, k: number): number {
240+
if (i > j) {
241+
return 0;
242+
}
243+
if (i === j) {
244+
return 1;
245+
}
246+
247+
if (f[i][j][k] !== -1) {
248+
return f[i][j][k];
249+
}
250+
251+
let res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k));
252+
const d = Math.abs(sCodes[i] - sCodes[j]);
253+
const t = Math.min(d, 26 - d);
254+
if (t <= k) {
255+
res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t));
256+
}
257+
return (f[i][j][k] = res);
258+
}
259+
260+
return dfs(0, n - 1, k);
261+
}
100262
```
101263

102264
<!-- tabs:end -->

0 commit comments

Comments
 (0)