Hard
You are given a 0-indexed string s
and an integer k
.
You are to perform the following partitioning operations until s
is empty:
s
containing at most k
distinct characters.s
and increase the number of partitions by one. The remaining characters (if any) in s
maintain their initial order.Before the operations, you are allowed to change at most one index in s
to another lowercase English letter.
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: In this example, to maximize the number of resulting partitions, s[2] can be changed to ‘b’. s becomes “acbca”. The operations can now be performed as follows until s becomes empty:
Hence, the answer is 3. It can be shown that it is not possible to obtain more than 3 partitions.
Example 2:
Input: s = “aabaab”, k = 3
Output: 1
Explanation: In this example, to maximize the number of resulting partitions we can leave s as it is. The operations can now be performed as follows until s becomes empty:
Hence, the answer is 1. It can be shown that it is not possible to obtain more than 1 partition.
Example 3:
Input: s = “xxyz”, k = 1
Output: 4
Explanation: In this example, to maximize the number of resulting partitions, s[1] can be changed to ‘a’. s becomes “xayz”. The operations can now be performed as follows until s becomes empty:
Hence, the answer is 4. It can be shown that it is not possible to obtain more than 4 partitions.
Constraints:
1 <= s.length <= 104
s
consists only of lowercase English letters.1 <= k <= 26
@SuppressWarnings("java:S6541")
public class Solution {
private static final int ALPHABET_SIZE = 'z' - 'a' + 1;
public int maxPartitionsAfterOperations(String s, int k) {
if (k == ALPHABET_SIZE) {
return 1;
}
int n = s.length();
int[] ansr = new int[n];
int[] usedr = new int[n];
int used = 0;
int cntUsed = 0;
int ans = 1;
for (int i = n - 1; i >= 0; --i) {
int ch = s.charAt(i) - 'a';
if ((used & (1 << ch)) == 0) {
if (cntUsed == k) {
cntUsed = 0;
used = 0;
ans++;
}
used |= (1 << ch);
cntUsed++;
}
ansr[i] = ans;
usedr[i] = used;
}
int ansl = 0;
ans = ansr[0];
int l = 0;
while (l < n) {
used = 0;
cntUsed = 0;
int usedBeforeLast = 0;
int usedTwiceBeforeLast = 0;
int last = -1;
int r = l;
while (r < n) {
int ch = s.charAt(r) - 'a';
if ((used & (1 << ch)) == 0) {
if (cntUsed == k) {
break;
}
usedBeforeLast = used;
last = r;
used |= (1 << ch);
cntUsed++;
} else if (cntUsed < k) {
usedTwiceBeforeLast |= (1 << ch);
}
r++;
}
if (cntUsed == k) {
if (last - l > Integer.bitCount(usedBeforeLast)) {
ans = Math.max(ans, ansl + 1 + ansr[last]);
}
if (last + 1 < r) {
if (last + 2 >= n) {
ans = Math.max(ans, ansl + 1 + 1);
} else {
if (Integer.bitCount(usedr[last + 2]) == k) {
int canUse = ((1 << ALPHABET_SIZE) - 1) & ~used & ~usedr[last + 2];
if (canUse > 0) {
ans = Math.max(ans, ansl + 1 + 1 + ansr[last + 2]);
} else {
ans = Math.max(ans, ansl + 1 + ansr[last + 2]);
}
int l1 = s.charAt(last + 1) - 'a';
if ((usedTwiceBeforeLast & (1 << l1)) == 0) {
ans = Math.max(ans, ansl + 1 + ansr[last + 1]);
}
} else {
ans = Math.max(ans, ansl + 1 + ansr[last + 2]);
}
}
}
}
l = r;
ansl++;
}
return ans;
}
}