diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README.md b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README.md index f9158de5aea6a..017ac4c1e757a 100644 --- a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README.md +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README.md @@ -77,32 +77,194 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3400-3499/3472.Lo -### 方法一 +### 方法一:记忆化搜索 + +我们设计一个函数 $\textit{dfs}(i, j, k)$,表示在字符串 $s[i..j]$ 中最多可以进行 $k$ 次操作,得到的最长回文子序列的长度。那么答案为 $\textit{dfs}(0, n - 1, k)$。 + +函数 $\textit{dfs}(i, j, k)$ 的计算过程如下: + +- 如果 $i > j$,返回 $0$; +- 如果 $i = j$,返回 $1$; +- 否则,我们可以忽略 $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 码差值。 +- 返回上述三种情况的最大值。 + +为了避免重复计算,我们使用记忆化搜索的方法。 + +时间复杂度 $O(n^2 \times k)$,空间复杂度 $O(n^2 \times k)$。其中 $n$ 是字符串 $s$ 的长度。 #### Python3 ```python - +class Solution: + def longestPalindromicSubsequence(self, s: str, k: int) -> int: + @cache + def dfs(i: int, j: int, k: int) -> int: + if i > j: + return 0 + if i == j: + return 1 + res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)) + d = abs(s[i] - s[j]) + t = min(d, 26 - d) + if t <= k: + res = max(res, dfs(i + 1, j - 1, k - t) + 2) + return res + + s = list(map(ord, s)) + n = len(s) + ans = dfs(0, n - 1, k) + dfs.cache_clear() + return ans ``` #### Java ```java - +class Solution { + private char[] s; + private Integer[][][] f; + + public int longestPalindromicSubsequence(String s, int k) { + this.s = s.toCharArray(); + int n = s.length(); + f = new Integer[n][n][k + 1]; + return dfs(0, n - 1, k); + } + + private int dfs(int i, int j, int k) { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != null) { + return f[i][j][k]; + } + int res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = Math.abs(s[i] - s[j]); + int t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + f[i][j][k] = res; + return res; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int longestPalindromicSubsequence(string s, int k) { + int n = s.size(); + vector f(n, vector(n, vector(k + 1, -1))); + auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != -1) { + return f[i][j][k]; + } + int res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = abs(s[i] - s[j]); + int t = min(d, 26 - d); + if (t <= k) { + res = max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return f[i][j][k] = res; + }; + return dfs(0, n - 1, k); + } +}; ``` #### Go ```go +func longestPalindromicSubsequence(s string, k int) int { + n := len(s) + f := make([][][]int, n) + for i := range f { + f[i] = make([][]int, n) + for j := range f[i] { + f[i][j] = make([]int, k+1) + for l := range f[i][j] { + f[i][j][l] = -1 + } + } + } + var dfs func(int, int, int) int + dfs = func(i, j, k int) int { + if i > j { + return 0 + } + if i == j { + return 1 + } + if f[i][j][k] != -1 { + return f[i][j][k] + } + res := max(dfs(i+1, j, k), dfs(i, j-1, k)) + d := abs(int(s[i]) - int(s[j])) + t := min(d, 26-d) + if t <= k { + res = max(res, 2+dfs(i+1, j-1, k-t)) + } + f[i][j][k] = res + return res + } + return dfs(0, n-1, k) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} +``` +#### TypeScript + +```ts +function longestPalindromicSubsequence(s: string, k: number): number { + const n = s.length; + const sCodes = s.split('').map(c => c.charCodeAt(0)); + const f: number[][][] = Array.from({ length: n }, () => + Array.from({ length: n }, () => Array(k + 1).fill(-1)), + ); + + function dfs(i: number, j: number, k: number): number { + if (i > j) { + return 0; + } + if (i === j) { + return 1; + } + + if (f[i][j][k] !== -1) { + return f[i][j][k]; + } + + let res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + const d = Math.abs(sCodes[i] - sCodes[j]); + const t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return (f[i][j][k] = res); + } + + return dfs(0, n - 1, k); +} ``` diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README_EN.md b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README_EN.md index 3a24676005095..7b7a567e06f6d 100644 --- a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README_EN.md +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/README_EN.md @@ -71,32 +71,194 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3400-3499/3472.Lo -### Solution 1 +### Solution 1: Memoized Search + +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)$. + +The calculation process of the function $\textit{dfs}(i, j, k)$ is as follows: + +- If $i > j$, return $0$; +- If $i = j$, return $1$; +- 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]$. +- Return the maximum value of the above three cases. + +To avoid repeated calculations, we use memoized search. + +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$. #### Python3 ```python - +class Solution: + def longestPalindromicSubsequence(self, s: str, k: int) -> int: + @cache + def dfs(i: int, j: int, k: int) -> int: + if i > j: + return 0 + if i == j: + return 1 + res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)) + d = abs(s[i] - s[j]) + t = min(d, 26 - d) + if t <= k: + res = max(res, dfs(i + 1, j - 1, k - t) + 2) + return res + + s = list(map(ord, s)) + n = len(s) + ans = dfs(0, n - 1, k) + dfs.cache_clear() + return ans ``` #### Java ```java - +class Solution { + private char[] s; + private Integer[][][] f; + + public int longestPalindromicSubsequence(String s, int k) { + this.s = s.toCharArray(); + int n = s.length(); + f = new Integer[n][n][k + 1]; + return dfs(0, n - 1, k); + } + + private int dfs(int i, int j, int k) { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != null) { + return f[i][j][k]; + } + int res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = Math.abs(s[i] - s[j]); + int t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + f[i][j][k] = res; + return res; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int longestPalindromicSubsequence(string s, int k) { + int n = s.size(); + vector f(n, vector(n, vector(k + 1, -1))); + auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != -1) { + return f[i][j][k]; + } + int res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = abs(s[i] - s[j]); + int t = min(d, 26 - d); + if (t <= k) { + res = max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return f[i][j][k] = res; + }; + return dfs(0, n - 1, k); + } +}; ``` #### Go ```go +func longestPalindromicSubsequence(s string, k int) int { + n := len(s) + f := make([][][]int, n) + for i := range f { + f[i] = make([][]int, n) + for j := range f[i] { + f[i][j] = make([]int, k+1) + for l := range f[i][j] { + f[i][j][l] = -1 + } + } + } + var dfs func(int, int, int) int + dfs = func(i, j, k int) int { + if i > j { + return 0 + } + if i == j { + return 1 + } + if f[i][j][k] != -1 { + return f[i][j][k] + } + res := max(dfs(i+1, j, k), dfs(i, j-1, k)) + d := abs(int(s[i]) - int(s[j])) + t := min(d, 26-d) + if t <= k { + res = max(res, 2+dfs(i+1, j-1, k-t)) + } + f[i][j][k] = res + return res + } + return dfs(0, n-1, k) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} +``` +#### TypeScript + +```ts +function longestPalindromicSubsequence(s: string, k: number): number { + const n = s.length; + const sCodes = s.split('').map(c => c.charCodeAt(0)); + const f: number[][][] = Array.from({ length: n }, () => + Array.from({ length: n }, () => Array(k + 1).fill(-1)), + ); + + function dfs(i: number, j: number, k: number): number { + if (i > j) { + return 0; + } + if (i === j) { + return 1; + } + + if (f[i][j][k] !== -1) { + return f[i][j][k]; + } + + let res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + const d = Math.abs(sCodes[i] - sCodes[j]); + const t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return (f[i][j][k] = res); + } + + return dfs(0, n - 1, k); +} ``` diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.cpp b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.cpp new file mode 100644 index 0000000000000..62e5107a91d42 --- /dev/null +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + int longestPalindromicSubsequence(string s, int k) { + int n = s.size(); + vector f(n, vector(n, vector(k + 1, -1))); + auto dfs = [&](this auto&& dfs, int i, int j, int k) -> int { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != -1) { + return f[i][j][k]; + } + int res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = abs(s[i] - s[j]); + int t = min(d, 26 - d); + if (t <= k) { + res = max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return f[i][j][k] = res; + }; + return dfs(0, n - 1, k); + } +}; diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.go b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.go new file mode 100644 index 0000000000000..d047d70ff1eb9 --- /dev/null +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.go @@ -0,0 +1,41 @@ +func longestPalindromicSubsequence(s string, k int) int { + n := len(s) + f := make([][][]int, n) + for i := range f { + f[i] = make([][]int, n) + for j := range f[i] { + f[i][j] = make([]int, k+1) + for l := range f[i][j] { + f[i][j][l] = -1 + } + } + } + var dfs func(int, int, int) int + dfs = func(i, j, k int) int { + if i > j { + return 0 + } + if i == j { + return 1 + } + if f[i][j][k] != -1 { + return f[i][j][k] + } + res := max(dfs(i+1, j, k), dfs(i, j-1, k)) + d := abs(int(s[i]) - int(s[j])) + t := min(d, 26-d) + if t <= k { + res = max(res, 2+dfs(i+1, j-1, k-t)) + } + f[i][j][k] = res + return res + } + return dfs(0, n-1, k) +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x +} diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.java b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.java new file mode 100644 index 0000000000000..9531df7d8ea03 --- /dev/null +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.java @@ -0,0 +1,31 @@ +class Solution { + private char[] s; + private Integer[][][] f; + + public int longestPalindromicSubsequence(String s, int k) { + this.s = s.toCharArray(); + int n = s.length(); + f = new Integer[n][n][k + 1]; + return dfs(0, n - 1, k); + } + + private int dfs(int i, int j, int k) { + if (i > j) { + return 0; + } + if (i == j) { + return 1; + } + if (f[i][j][k] != null) { + return f[i][j][k]; + } + int res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + int d = Math.abs(s[i] - s[j]); + int t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + f[i][j][k] = res; + return res; + } +} diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.py b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.py new file mode 100644 index 0000000000000..ba4f36f9b1eb7 --- /dev/null +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.py @@ -0,0 +1,20 @@ +class Solution: + def longestPalindromicSubsequence(self, s: str, k: int) -> int: + @cache + def dfs(i: int, j: int, k: int) -> int: + if i > j: + return 0 + if i == j: + return 1 + res = max(dfs(i + 1, j, k), dfs(i, j - 1, k)) + d = abs(s[i] - s[j]) + t = min(d, 26 - d) + if t <= k: + res = max(res, dfs(i + 1, j - 1, k - t) + 2) + return res + + s = list(map(ord, s)) + n = len(s) + ans = dfs(0, n - 1, k) + dfs.cache_clear() + return ans diff --git a/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.ts b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.ts new file mode 100644 index 0000000000000..a3384d6e28b45 --- /dev/null +++ b/solution/3400-3499/3472.Longest Palindromic Subsequence After at Most K Operations/Solution.ts @@ -0,0 +1,30 @@ +function longestPalindromicSubsequence(s: string, k: number): number { + const n = s.length; + const sCodes = s.split('').map(c => c.charCodeAt(0)); + const f: number[][][] = Array.from({ length: n }, () => + Array.from({ length: n }, () => Array(k + 1).fill(-1)), + ); + + function dfs(i: number, j: number, k: number): number { + if (i > j) { + return 0; + } + if (i === j) { + return 1; + } + + if (f[i][j][k] !== -1) { + return f[i][j][k]; + } + + let res = Math.max(dfs(i + 1, j, k), dfs(i, j - 1, k)); + const d = Math.abs(sCodes[i] - sCodes[j]); + const t = Math.min(d, 26 - d); + if (t <= k) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, k - t)); + } + return (f[i][j][k] = res); + } + + return dfs(0, n - 1, k); +}