From 71feb5cc1c8a47179ee696021b525a3549ec0536 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Tue, 25 Feb 2025 16:34:06 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1745 No.1745.Palindrome Partitioning IV --- .../1745.Palindrome Partitioning IV/README.md | 79 ++++++++++++++----- .../README_EN.md | 79 ++++++++++++++----- .../Solution.cpp | 8 +- .../Solution.go | 16 ++-- .../Solution.java | 12 +-- .../Solution.py | 6 +- .../Solution.ts | 17 ++++ 7 files changed, 156 insertions(+), 61 deletions(-) create mode 100644 solution/1700-1799/1745.Palindrome Partitioning IV/Solution.ts diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/README.md b/solution/1700-1799/1745.Palindrome Partitioning IV/README.md index ca291ecba0c23..d60f27cb33f5d 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/README.md +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/README.md @@ -56,11 +56,26 @@ tags: -### 方法一:预处理 + 枚举 +### 方法一:动态规划 -预处理出字符串 `s` 的所有子串是否为回文串,然后枚举 `s` 的所有分割点,判断是否满足条件。 +我们定义 $f[i][j]$ 表示字符串 $s$ 的第 $i$ 个字符到第 $j$ 个字符是否为回文串,初始时 $f[i][j] = \textit{true}$。 -时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 `s` 的长度。 +然后我们可以通过以下的状态转移方程来计算 $f[i][j]$: + +$$ +f[i][j] = \begin{cases} +\textit{true}, & \text{if } s[i] = s[j] \text{ and } (i + 1 = j \text{ or } f[i + 1][j - 1]) \\ +\textit{false}, & \text{otherwise} +\end{cases} +$$ + +由于 $f[i][j]$ 依赖于 $f[i + 1][j - 1]$,因此,我们需要从大到小的顺序枚举 $i$,从小到大的顺序枚举 $j$,这样才能保证当计算 $f[i][j]$ 时 $f[i + 1][j - 1]$ 已经被计算过。 + +接下来,我们枚举第一个子串的右端点 $i$,第二个子串的右端点 $j$,那么第三个子串的左端点可以枚举的范围为 $[j + 1, n - 1]$,其中 $n$ 是字符串 $s$ 的长度。如果第一个子串 $s[0..i]$、第二个子串 $s[i+1..j]$ 和第三个子串 $s[j+1..n-1]$ 都是回文串,那么我们就找到了一种可行的分割方案,返回 $\textit{true}$。 + +枚举完所有的分割方案后,如果没有找到符合要求的分割方案,那么返回 $\textit{false}$。 + +时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是字符串 $s$ 的长度。 @@ -70,13 +85,13 @@ tags: class Solution: def checkPartitioning(self, s: str) -> bool: n = len(s) - g = [[True] * n for _ in range(n)] + f = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): - g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1]) + f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1]) for i in range(n - 2): for j in range(i + 1, n - 1): - if g[0][i] and g[i + 1][j] and g[j + 1][-1]: + if f[0][i] and f[i + 1][j] and f[j + 1][-1]: return True return False ``` @@ -87,18 +102,18 @@ class Solution: class Solution { public boolean checkPartitioning(String s) { int n = s.length(); - boolean[][] g = new boolean[n][n]; - for (var e : g) { - Arrays.fill(e, true); + boolean[][] f = new boolean[n][n]; + for (var g : f) { + Arrays.fill(g, true); } for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } @@ -115,15 +130,15 @@ class Solution { public: bool checkPartitioning(string s) { int n = s.size(); - vector> g(n, vector(n, true)); + vector> f(n, vector(n, true)); for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } @@ -138,21 +153,21 @@ public: ```go func checkPartitioning(s string) bool { n := len(s) - g := make([][]bool, n) - for i := range g { - g[i] = make([]bool, n) - for j := range g[i] { - g[i][j] = true + f := make([][]bool, n) + for i := range f { + f[i] = make([]bool, n) + for j := range f[i] { + f[i][j] = true } } for i := n - 1; i >= 0; i-- { for j := i + 1; j < n; j++ { - g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1]) + f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1]) } } for i := 0; i < n-2; i++ { for j := i + 1; j < n-1; j++ { - if g[0][i] && g[i+1][j] && g[j+1][n-1] { + if f[0][i] && f[i+1][j] && f[j+1][n-1] { return true } } @@ -161,6 +176,28 @@ func checkPartitioning(s string) bool { } ``` +#### TypeScript + +```ts +function checkPartitioning(s: string): boolean { + const n = s.length; + const f: boolean[][] = Array.from({ length: n }, () => Array(n).fill(true)); + for (let i = n - 1; i >= 0; --i) { + for (let j = i + 1; j < n; ++j) { + f[i][j] = s[i] === s[j] && f[i + 1][j - 1]; + } + } + for (let i = 0; i < n - 2; ++i) { + for (let j = i + 1; j < n - 1; ++j) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { + return true; + } + } + } + return false; +} +``` + diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/README_EN.md b/solution/1700-1799/1745.Palindrome Partitioning IV/README_EN.md index fa7e699680b23..6d10b285d0c61 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/README_EN.md +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/README_EN.md @@ -54,7 +54,26 @@ tags: -### Solution 1 +### Solution 1: Dynamic Programming + +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}$. + +Then we can calculate $f[i][j]$ using the following state transition equation: + +$$ +f[i][j] = \begin{cases} +\textit{true}, & \text{if } s[i] = s[j] \text{ and } (i + 1 = j \text{ or } f[i + 1][j - 1]) \\ +\textit{false}, & \text{otherwise} +\end{cases} +$$ + +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. + +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}$. + +After enumerating all partitioning schemes, if no valid partitioning scheme is found, return $\textit{false}$. + +Time complexity is $O(n^2)$, and space complexity is $O(n^2)$. Where $n$ is the length of the string $s$. @@ -64,13 +83,13 @@ tags: class Solution: def checkPartitioning(self, s: str) -> bool: n = len(s) - g = [[True] * n for _ in range(n)] + f = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): - g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1]) + f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1]) for i in range(n - 2): for j in range(i + 1, n - 1): - if g[0][i] and g[i + 1][j] and g[j + 1][-1]: + if f[0][i] and f[i + 1][j] and f[j + 1][-1]: return True return False ``` @@ -81,18 +100,18 @@ class Solution: class Solution { public boolean checkPartitioning(String s) { int n = s.length(); - boolean[][] g = new boolean[n][n]; - for (var e : g) { - Arrays.fill(e, true); + boolean[][] f = new boolean[n][n]; + for (var g : f) { + Arrays.fill(g, true); } for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } @@ -109,15 +128,15 @@ class Solution { public: bool checkPartitioning(string s) { int n = s.size(); - vector> g(n, vector(n, true)); + vector> f(n, vector(n, true)); for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } @@ -132,21 +151,21 @@ public: ```go func checkPartitioning(s string) bool { n := len(s) - g := make([][]bool, n) - for i := range g { - g[i] = make([]bool, n) - for j := range g[i] { - g[i][j] = true + f := make([][]bool, n) + for i := range f { + f[i] = make([]bool, n) + for j := range f[i] { + f[i][j] = true } } for i := n - 1; i >= 0; i-- { for j := i + 1; j < n; j++ { - g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1]) + f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1]) } } for i := 0; i < n-2; i++ { for j := i + 1; j < n-1; j++ { - if g[0][i] && g[i+1][j] && g[j+1][n-1] { + if f[0][i] && f[i+1][j] && f[j+1][n-1] { return true } } @@ -155,6 +174,28 @@ func checkPartitioning(s string) bool { } ``` +#### TypeScript + +```ts +function checkPartitioning(s: string): boolean { + const n = s.length; + const f: boolean[][] = Array.from({ length: n }, () => Array(n).fill(true)); + for (let i = n - 1; i >= 0; --i) { + for (let j = i + 1; j < n; ++j) { + f[i][j] = s[i] === s[j] && f[i + 1][j - 1]; + } + } + for (let i = 0; i < n - 2; ++i) { + for (let j = i + 1; j < n - 1; ++j) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { + return true; + } + } + } + return false; +} +``` + diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.cpp b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.cpp index a0bbb35aa4259..d46f12471f0aa 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.cpp +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.cpp @@ -2,19 +2,19 @@ class Solution { public: bool checkPartitioning(string s) { int n = s.size(); - vector> g(n, vector(n, true)); + vector> f(n, vector(n, true)); for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s[i] == s[j] && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s[i] == s[j] && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } } return false; } -}; \ No newline at end of file +}; diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.go b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.go index 0f6c285b9e741..7346b032f8e96 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.go +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.go @@ -1,23 +1,23 @@ func checkPartitioning(s string) bool { n := len(s) - g := make([][]bool, n) - for i := range g { - g[i] = make([]bool, n) - for j := range g[i] { - g[i][j] = true + f := make([][]bool, n) + for i := range f { + f[i] = make([]bool, n) + for j := range f[i] { + f[i][j] = true } } for i := n - 1; i >= 0; i-- { for j := i + 1; j < n; j++ { - g[i][j] = s[i] == s[j] && (i+1 == j || g[i+1][j-1]) + f[i][j] = s[i] == s[j] && (i+1 == j || f[i+1][j-1]) } } for i := 0; i < n-2; i++ { for j := i + 1; j < n-1; j++ { - if g[0][i] && g[i+1][j] && g[j+1][n-1] { + if f[0][i] && f[i+1][j] && f[j+1][n-1] { return true } } } return false -} \ No newline at end of file +} diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.java b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.java index 271ab15679f0d..22413560623d3 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.java +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.java @@ -1,22 +1,22 @@ class Solution { public boolean checkPartitioning(String s) { int n = s.length(); - boolean[][] g = new boolean[n][n]; - for (var e : g) { - Arrays.fill(e, true); + boolean[][] f = new boolean[n][n]; + for (var g : f) { + Arrays.fill(g, true); } for (int i = n - 1; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { - g[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || g[i + 1][j - 1]); + f[i][j] = s.charAt(i) == s.charAt(j) && (i + 1 == j || f[i + 1][j - 1]); } } for (int i = 0; i < n - 2; ++i) { for (int j = i + 1; j < n - 1; ++j) { - if (g[0][i] && g[i + 1][j] && g[j + 1][n - 1]) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { return true; } } } return false; } -} \ No newline at end of file +} diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.py b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.py index 9bfdd0f75c69c..6579173bc2185 100644 --- a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.py +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.py @@ -1,12 +1,12 @@ class Solution: def checkPartitioning(self, s: str) -> bool: n = len(s) - g = [[True] * n for _ in range(n)] + f = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): - g[i][j] = s[i] == s[j] and (i + 1 == j or g[i + 1][j - 1]) + f[i][j] = s[i] == s[j] and (i + 1 == j or f[i + 1][j - 1]) for i in range(n - 2): for j in range(i + 1, n - 1): - if g[0][i] and g[i + 1][j] and g[j + 1][-1]: + if f[0][i] and f[i + 1][j] and f[j + 1][-1]: return True return False diff --git a/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.ts b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.ts new file mode 100644 index 0000000000000..ec63c49c7d2ce --- /dev/null +++ b/solution/1700-1799/1745.Palindrome Partitioning IV/Solution.ts @@ -0,0 +1,17 @@ +function checkPartitioning(s: string): boolean { + const n = s.length; + const f: boolean[][] = Array.from({ length: n }, () => Array(n).fill(true)); + for (let i = n - 1; i >= 0; --i) { + for (let j = i + 1; j < n; ++j) { + f[i][j] = s[i] === s[j] && f[i + 1][j - 1]; + } + } + for (let i = 0; i < n - 2; ++i) { + for (let j = i + 1; j < n - 1; ++j) { + if (f[0][i] && f[i + 1][j] && f[j + 1][n - 1]) { + return true; + } + } + } + return false; +}