First, you are allowed to change at mostone index in s to another lowercase English letter.
After that, do the following partitioning operation until s is empty:
Choose the longestprefix of s containing at most kdistinct characters.
Delete the prefix from s and increase the number of partitions by one. The remaining characters (if any) in s maintain their initial order.
Return an integer denoting the maximum number of resulting partitions after the operations by optimally choosing at most one index to change.
Example 1:
Input:s = "accca", k = 2
Output:3
Explanation:
The optimal way is to change s[2] to something other than a and c, for example, b. then it becomes "acbca".
Then we perform the operations:
The longest prefix containing at most 2 distinct characters is "ac", we remove it and s becomes "bca".
Now The longest prefix containing at most 2 distinct characters is "bc", so we remove it and s becomes "a".
Finally, we remove "a" and s becomes empty, so the procedure ends.
Doing the operations, the string is divided into 3 partitions, so the answer is 3.
Example 2:
Input:s = "aabaab", k = 3
Output:1
Explanation:
Initially s contains 2 distinct characters, so whichever character we change, it will contain at most 3 distinct characters, so the longest prefix with at most 3 distinct characters would always be all of it, therefore the answer is 1.
Example 3:
Input:s = "xxyz", k = 1
Output:4
Explanation:
The optimal way is to change s[0] or s[1] to something other than characters in s, for example, to change s[0] to w.
Then s becomes "wxyz", which consists of 4 distinct characters, so as k is 1, it will divide into 4 partitions.
Constraints:
1 <= s.length <= 104
s consists only of lowercase English letters.
1 <= k <= 26
Solutions
Solution 1: Memoized Search
Thinking
\(n \le 10^4\) and we may change one character. Trying every change and resimulating partitions is about \(O(n^2 |\Sigma|)\), which is tight.
A cut happens only when the current segment’s distinct-letter set exceeds \(k\). That set is a \(26\)-bit mask and the remaining change is \(0\) or \(1\), so memoization is feasible.
We therefore search \(\textit{dfs}(i, \textit{cur}, t)\): index \(i\), segment mask \(\textit{cur}\), \(t\) changes left. Adding \(s[i]\) opens a new segment when the popcount exceeds \(k\); if a change remains, we also try every replacement letter.
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:
If \(i \geq n\), it means we have finished processing string \(s\), return 1.
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\).
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)\).
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.
Use a hash table to cache already computed states to avoid redundant calculations.
The time complexity is \(O(n|\Sigma|k)\), and the space complexity is \(O(n|\Sigma|k)\), where \(n\) is the length of string \(s\), and \(|\Sigma|\) is the size of the character set.
\(n \le 10^4\) and at most one character may change. Trying every change and then cutting the longest valid prefixes is about \(O(n^2 |\Sigma|)\), which is tight.
The unchanged transition always calls the next index first. The chain from index \(0\) to \(n\) has length \(n\). Python raises RecursionError at \(n=1500\), and Java and Node overflow at \(n=8000\).
A segment is cut when it would contain more than \(k\) distinct letters, and only one change is available, so few masks are actually reached at one index. Each state also depends only on the next index.
Record the reachable pairs \((\textit{cur}, t)\) from the left, then fill their maximum partition counts from the right. A finished string is worth \(1\). If adding the current letter exceeds \(k\), open a new segment and add \(1\); while a change remains, also try every replacement letter.
State \((\textit{cur}, t)\) means the open segment already contains the letter mask \(\textit{cur}\), and \(t\) changes remain. The answer is the value of \((0, 1)\) at index \(0\).
First mark the states reachable at every index, starting from \((0, 1)\). Let \(v = 1 \ll (s[i] - 'a')\) be the bit of the current letter.
Let \(\textit{nxt} = \textit{cur} \mid v\). If \(\textit{nxt}\) has more than \(k\) bits, the open segment ends here: the next mask is \(v\) and \(t\) is unchanged. Otherwise the next mask is \(\textit{nxt}\).
If \(t = 1\), also replace \(s[i]\) by every lowercase letter. For letter \(j\), let \(\textit{nxt} = \textit{cur} \mid (1 \ll j)\). When that mask has more than \(k\) bits, the next state is mask \(1 \ll j\) with no change left. Otherwise the next state is mask \(\textit{nxt}\) with no change left.
Then let \(i\) run from \(n - 1\) down to \(0\) and evaluate the same transitions. At \(i = n\) the string is finished and the value is \(1\). A transition that cuts the open segment adds \(1\) to the successor's value.
The time complexity is \(O(n|\Sigma|k)\), and the space complexity is \(O(n|\Sigma|k)\), where \(n\) is the length of \(s\) and \(|\Sigma|\) is the alphabet size.