From 6d98befef81a50152bbb903f72375ce02b7dbfc1 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Mon, 3 Mar 2025 08:55:23 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1278 No.1278.Palindrome Partitioning III --- .../README.md | 76 +++++++++++++++++- .../README_EN.md | 78 ++++++++++++++++++- .../Solution.rs | 34 ++++++++ .../Solution.ts | 26 +++++++ 4 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 solution/1200-1299/1278.Palindrome Partitioning III/Solution.rs create mode 100644 solution/1200-1299/1278.Palindrome Partitioning III/Solution.ts diff --git a/solution/1200-1299/1278.Palindrome Partitioning III/README.md b/solution/1200-1299/1278.Palindrome Partitioning III/README.md index 668e0adbbea71..39fb5f8bb65a3 100644 --- a/solution/1200-1299/1278.Palindrome Partitioning III/README.md +++ b/solution/1200-1299/1278.Palindrome Partitioning III/README.md @@ -68,11 +68,11 @@ tags: ### 方法一:动态规划 -定义 $dp[i][j]$ 表示将字符串 $s$ 的前 $i$ 个字符分割成 $j$ 个回文串所需要的最少修改次数,我们假定 $i$ 下标从 $1$ 开始,答案为 $dp[n][k]$。 +我们定义 $f[i][j]$ 表示将字符串 $s$ 的前 $i$ 个字符分割成 $j$ 个回文串所需要的最少修改次数,我们假定 $i$ 下标从 $1$ 开始,答案为 $f[n][k]$。 -对于 $dp[i][j]$,我们可以枚举第 $j-1$ 个回文串的最后一个字符的位置 $h$,那么 $dp[i][j]$ 就等于 $dp[h][j-1] + g[h][i-1]$ 的较小值,其中 $g[h][i-1]$ 表示将字符串 $s[h..i-1]$ 变成回文串所需要的最少修改次数(这一部分我们可以通过预处理得到,时间复杂度 $O(n^2)$。 +对于 $f[i][j]$,我们可以枚举第 $j-1$ 个回文串的最后一个字符的位置 $h$,那么 $f[i][j]$ 就等于 $f[h][j-1] + g[h][i-1]$ 的较小值,其中 $g[h][i-1]$ 表示将字符串 $s[h..i-1]$ 变成回文串所需要的最少修改次数(这一部分我们可以通过预处理得到,时间复杂度 $O(n^2)$。 -时间复杂度 $O(n^2\times k)$。其中 $n$ 为字符串 $s$ 的长度。 +时间复杂度 $O(n^2 \times k)$,空间复杂度 $O(n \times (n + k))$。其中 $n$ 为字符串 $s$ 的长度。 @@ -205,6 +205,76 @@ func palindromePartition(s string, k int) int { } ``` +#### TypeScript + +```ts +function palindromePartition(s: string, k: number): number { + const n = s.length; + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(0)); + for (let i = n - 1; i >= 0; i--) { + for (let j = i + 1; j < n; j++) { + g[i][j] = s[i] !== s[j] ? 1 : 0; + if (i + 1 < j) { + g[i][j] += g[i + 1][j - 1]; + } + } + } + const f: number[][] = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= Math.min(i, k); j++) { + if (j === 1) { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = 1 << 30; + for (let h = j - 1; h < i; h++) { + f[i][j] = Math.min(f[i][j], f[h][j - 1] + g[h][i - 1]); + } + } + } + } + return f[n][k]; +} +``` + +#### Rust + +```rust +impl Solution { + pub fn palindrome_partition(s: String, k: i32) -> i32 { + let n = s.len(); + let s: Vec = s.chars().collect(); + let mut g = vec![vec![0; n]; n]; + + for i in (0..n).rev() { + for j in i + 1..n { + g[i][j] = if s[i] != s[j] { 1 } else { 0 }; + if i + 1 < j { + g[i][j] += g[i + 1][j - 1]; + } + } + } + + let mut f = vec![vec![0; (k + 1) as usize]; n + 1]; + let inf = i32::MAX; + + for i in 1..=n { + for j in 1..=i.min(k as usize) { + if j == 1 { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = inf; + for h in (j - 1)..i { + f[i][j] = f[i][j].min(f[h][j - 1] + g[h][i - 1]); + } + } + } + } + + f[n][k as usize] + } +} +``` + diff --git a/solution/1200-1299/1278.Palindrome Partitioning III/README_EN.md b/solution/1200-1299/1278.Palindrome Partitioning III/README_EN.md index 467b764025869..44462d146821b 100644 --- a/solution/1200-1299/1278.Palindrome Partitioning III/README_EN.md +++ b/solution/1200-1299/1278.Palindrome Partitioning III/README_EN.md @@ -65,7 +65,13 @@ tags: -### Solution 1 +### Solution 1: Dynamic Programming + +We define $f[i][j]$ to represent the minimum number of changes needed to partition the first $i$ characters of the string $s$ into $j$ palindromic substrings. We assume the index $i$ starts from 1, and the answer is $f[n][k]$. + +For $f[i][j]$, we can enumerate the position $h$ of the last character of the $(j-1)$-th palindromic substring. Then $f[i][j]$ is equal to the minimum value of $f[h][j-1] + g[h][i-1]$, where $g[h][i-1]$ represents the minimum number of changes needed to turn the substring $s[h..i-1]$ into a palindrome (this part can be preprocessed with a time complexity of $O(n^2)$). + +The time complexity is $O(n^2 \times k)$, and the space complexity is $O(n \times (n + k))$. Where $n$ is the length of the string $s$. @@ -198,6 +204,76 @@ func palindromePartition(s string, k int) int { } ``` +#### TypeScript + +```ts +function palindromePartition(s: string, k: number): number { + const n = s.length; + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(0)); + for (let i = n - 1; i >= 0; i--) { + for (let j = i + 1; j < n; j++) { + g[i][j] = s[i] !== s[j] ? 1 : 0; + if (i + 1 < j) { + g[i][j] += g[i + 1][j - 1]; + } + } + } + const f: number[][] = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= Math.min(i, k); j++) { + if (j === 1) { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = 1 << 30; + for (let h = j - 1; h < i; h++) { + f[i][j] = Math.min(f[i][j], f[h][j - 1] + g[h][i - 1]); + } + } + } + } + return f[n][k]; +} +``` + +#### Rust + +```rust +impl Solution { + pub fn palindrome_partition(s: String, k: i32) -> i32 { + let n = s.len(); + let s: Vec = s.chars().collect(); + let mut g = vec![vec![0; n]; n]; + + for i in (0..n).rev() { + for j in i + 1..n { + g[i][j] = if s[i] != s[j] { 1 } else { 0 }; + if i + 1 < j { + g[i][j] += g[i + 1][j - 1]; + } + } + } + + let mut f = vec![vec![0; (k + 1) as usize]; n + 1]; + let inf = i32::MAX; + + for i in 1..=n { + for j in 1..=i.min(k as usize) { + if j == 1 { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = inf; + for h in (j - 1)..i { + f[i][j] = f[i][j].min(f[h][j - 1] + g[h][i - 1]); + } + } + } + } + + f[n][k as usize] + } +} +``` + diff --git a/solution/1200-1299/1278.Palindrome Partitioning III/Solution.rs b/solution/1200-1299/1278.Palindrome Partitioning III/Solution.rs new file mode 100644 index 0000000000000..ca8ba46144ecb --- /dev/null +++ b/solution/1200-1299/1278.Palindrome Partitioning III/Solution.rs @@ -0,0 +1,34 @@ +impl Solution { + pub fn palindrome_partition(s: String, k: i32) -> i32 { + let n = s.len(); + let s: Vec = s.chars().collect(); + let mut g = vec![vec![0; n]; n]; + + for i in (0..n).rev() { + for j in i + 1..n { + g[i][j] = if s[i] != s[j] { 1 } else { 0 }; + if i + 1 < j { + g[i][j] += g[i + 1][j - 1]; + } + } + } + + let mut f = vec![vec![0; (k + 1) as usize]; n + 1]; + let inf = i32::MAX; + + for i in 1..=n { + for j in 1..=i.min(k as usize) { + if j == 1 { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = inf; + for h in (j - 1)..i { + f[i][j] = f[i][j].min(f[h][j - 1] + g[h][i - 1]); + } + } + } + } + + f[n][k as usize] + } +} diff --git a/solution/1200-1299/1278.Palindrome Partitioning III/Solution.ts b/solution/1200-1299/1278.Palindrome Partitioning III/Solution.ts new file mode 100644 index 0000000000000..79236ad0b6cda --- /dev/null +++ b/solution/1200-1299/1278.Palindrome Partitioning III/Solution.ts @@ -0,0 +1,26 @@ +function palindromePartition(s: string, k: number): number { + const n = s.length; + const g: number[][] = Array.from({ length: n }, () => Array(n).fill(0)); + for (let i = n - 1; i >= 0; i--) { + for (let j = i + 1; j < n; j++) { + g[i][j] = s[i] !== s[j] ? 1 : 0; + if (i + 1 < j) { + g[i][j] += g[i + 1][j - 1]; + } + } + } + const f: number[][] = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)); + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= Math.min(i, k); j++) { + if (j === 1) { + f[i][j] = g[0][i - 1]; + } else { + f[i][j] = 1 << 30; + for (let h = j - 1; h < i; h++) { + f[i][j] = Math.min(f[i][j], f[h][j - 1] + g[h][i - 1]); + } + } + } + } + return f[n][k]; +}