diff --git a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README.md b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README.md index 18c1e2d54aaa0..16d76ae8b2181 100644 --- a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README.md +++ b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README.md @@ -100,7 +100,19 @@ tags: -### 方法一 +### 方法一:记忆化搜索 + +我们设计一个函数 $\textit{dfs}(i, \textit{cur}, t)$ 表示当前处理到字符串 $s$ 的下标 $i$,当前前缀中已经包含的字符集合为 $\textit{cur}$,并且还可以修改 $t$ 次字符时,能够得到的最大分割数量。那么答案即为 $\textit{dfs}(0, 0, 1)$。 + +函数 $\textit{dfs}(i, \textit{cur}, t)$ 的执行逻辑如下: + +1. 如果 $i \geq n$,说明已经处理完字符串 $s$,返回 1。 +2. 计算当前字符 $s[i]$ 对应的位掩码 $v = 1 \ll (s[i] - 'a')$,并计算更新后的字符集合 $\textit{nxt} = \textit{cur} \mid v$。 +3. 如果 $\textit{nxt}$ 中的位数超过 $k$,说明当前前缀已经包含超过 $k$ 个不同字符,我们需要进行一次分割,此时分割数量加 1,并递归调用 $\textit{dfs}(i + 1, v, t)$;否则,继续递归调用 $\textit{dfs}(i + 1, \textit{nxt}, t)$。 +4. 如果 $t > 0$,说明我们还可以修改一次字符。我们尝试将当前字符 $s[i]$ 修改为任意一个小写字母(共 26 种选择),对于每个选择,计算更新后的字符集合 $\textit{nxt} = \textit{cur} \mid (1 \ll j)$,并根据是否超过 $k$ 个不同字符,选择相应的递归调用方式,更新最大分割数量。 +5. 使用哈希表缓存已经计算过的状态,避免重复计算。 + +时间复杂度 $O(n \times |\Sigma| \times k)$,空间复杂度 $O(n \times |\Sigma| \times k)$。其中 $n$ 为字符串 $s$ 的长度,而 $|\Sigma|$ 为字符集大小。 @@ -181,7 +193,7 @@ public: int maxPartitionsAfterOperations(string s, int k) { int n = s.size(); unordered_map f; - function dfs = [&](int i, int cur, int t) { + auto dfs = [&](this auto&& dfs, int i, int cur, int t) -> int { if (i >= n) { return 1; } diff --git a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README_EN.md b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README_EN.md index 68a74034f013e..444fd23e221fe 100644 --- a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README_EN.md +++ b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/README_EN.md @@ -98,7 +98,19 @@ tags: -### Solution 1 +### Solution 1: Memoized Search + +We design a function $\textit{dfs}(i, \textit{cur}, t)$ that represents the maximum number of partitions we can obtain when currently processing index $i$ of string $s$, the current prefix already contains the character set $\textit{cur}$, and we can still modify $t$ characters. Then the answer is $\textit{dfs}(0, 0, 1)$. + +The execution logic of function $\textit{dfs}(i, \textit{cur}, t)$ is as follows: + +1. If $i \geq n$, it means we have finished processing string $s$, return 1. +2. Calculate the bitmask $v = 1 \ll (s[i] - 'a')$ corresponding to the current character $s[i]$, and calculate the updated character set $\textit{nxt} = \textit{cur} \mid v$. +3. If the number of bits in $\textit{nxt}$ exceeds $k$, it means the current prefix already contains more than $k$ distinct characters. We need to make a partition, increment the partition count by 1, and recursively call $\textit{dfs}(i + 1, v, t)$. Otherwise, continue recursively calling $\textit{dfs}(i + 1, \textit{nxt}, t)$. +4. If $t > 0$, it means we can still modify a character once. We try to change the current character $s[i]$ to any lowercase letter (26 choices in total). For each choice, calculate the updated character set $\textit{nxt} = \textit{cur} \mid (1 \ll j)$, and based on whether it exceeds $k$ distinct characters, choose the corresponding recursive call method to update the maximum partition count. +5. Use a hash table to cache already computed states to avoid redundant calculations. + +The time complexity is $O(n \times |\Sigma| \times k)$ and the space complexity is $O(n \times |\Sigma| \times k)$, where $n$ is the length of string $s$, and $|\Sigma|$ is the size of the character set. @@ -179,7 +191,7 @@ public: int maxPartitionsAfterOperations(string s, int k) { int n = s.size(); unordered_map f; - function dfs = [&](int i, int cur, int t) { + auto dfs = [&](this auto&& dfs, int i, int cur, int t) -> int { if (i >= n) { return 1; } diff --git a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/Solution.cpp b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/Solution.cpp index 0023c8165d70f..8636a03dfa9cd 100644 --- a/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/Solution.cpp +++ b/solution/3000-3099/3003.Maximize the Number of Partitions After Operations/Solution.cpp @@ -3,7 +3,7 @@ class Solution { int maxPartitionsAfterOperations(string s, int k) { int n = s.size(); unordered_map f; - function dfs = [&](int i, int cur, int t) { + auto dfs = [&](this auto&& dfs, int i, int cur, int t) -> int { if (i >= n) { return 1; } @@ -28,4 +28,4 @@ class Solution { }; return dfs(0, 0, 1); } -}; \ No newline at end of file +};