执行操作后的最大分割数量
难度:
标签:
题目描述
You are given a 0-indexed string s
and an integer k
.
You are to perform the following partitioning operations until s
is empty:
- Choose the longest prefix of
s
containing at mostk
distinct characters. - Delete the prefix from
s
and increase the number of partitions by one. The remaining characters (if any) ins
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: - Choose the longest prefix containing at most 2 distinct characters, "acbca". - Delete the prefix, and s becomes "bca". The number of partitions is now 1. - Choose the longest prefix containing at most 2 distinct characters, "bca". - Delete the prefix, and s becomes "a". The number of partitions is now 2. - Choose the longest prefix containing at most 2 distinct characters, "a". - Delete the prefix, and s becomes empty. The number of partitions is now 3. 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: - Choose the longest prefix containing at most 3 distinct characters, "aabaab". - Delete the prefix, and s becomes empty. The number of partitions becomes 1. 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: - Choose the longest prefix containing at most 1 distinct character, "xayz". - Delete the prefix, and s becomes "ayz". The number of partitions is now 1. - Choose the longest prefix containing at most 1 distinct character, "ayz". - Delete the prefix, and s becomes "yz". The number of partitions is now 2. - Choose the longest prefix containing at most 1 distinct character, "yz". - Delete the prefix, and s becomes "z". The number of partitions is now 3. - Choose the longest prefix containing at most 1 distinct character, "z". - Delete the prefix, and s becomes empty. The number of partitions is now 4. 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
代码结果
运行时间: 61 ms, 内存: 17.3 MB
/*
* Problem: Given a string 's' and an integer 'k', find the maximum number of partitions
* after optionally changing at most one character, such that each partition's prefix contains
* at most 'k' different characters.
*
* Approach (Java Streams):
* 1. Use streams to try changing each character and calculate the partition count.
* 2. Use streams to count the number of partitions with at most 'k' unique characters.
*/
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.Arrays;
public class Solution {
public int maxPartitions(String s, int k) {
return Math.max(
// Maximum partitions without any modification
calculatePartitions(s, k),
// Maximum partitions with one modification
IntStream.range(0, s.length()).flatMap(i -> IntStream.range(0, 26)
.filter(c -> s.charAt(i) != (char) (c + 'a'))
.mapToObj(c -> s.substring(0, i) + (char) (c + 'a') + s.substring(i + 1))
.mapToInt(modified -> calculatePartitions(modified, k))
.max().orElse(0)
).max().orElse(0)
);
}
private int calculatePartitions(String s, int k) {
int[] count = new int[26];
int uniqueCount = 0, partitions = 0, left = 0;
for (int right = 0; right < s.length(); right++) {
if (count[s.charAt(right) - 'a']++ == 0) uniqueCount++;
while (uniqueCount > k) {
if (--count[s.charAt(left++) - 'a'] == 0) uniqueCount--;
}
if (uniqueCount <= k) partitions++;
}
return partitions;
}
}
解释
方法:
这道题的核心是通过一次或不通过修改任何字符,来最大化字符串s的分割次数。首先,如果k等于26(字母表的长度),可以一次性删除整个字符串,所以答案为1。题解使用两个遍历过程:首先,从右向左遍历字符串,记录每个位置为起始点的段数和所包含的字符(使用位掩码表示)。然后,再从左向右遍历字符串,并结合已存储的后缀信息来决定修改字符的位置,以最大化分割数。第二遍遍历尝试通过字符替换来优化可能的分割方式,最终更新并返回最大分割数。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
如何确保修改最多一处字符就可以实现最大分割数的策略?题解中似乎没有明确说明这一点。
▷🦆
在题解中提到的位掩码是如何工作的,尤其是在处理字符集时这种表示法有什么优势?
▷🦆
题解中提到的两次遍历各自的目的是什么?第一次遍历从右向左,第二次遍历从左向右,这样做的具体原因是?
▷🦆
题解中的函数`update`似乎是用来更新字符掩码和段数,但如果遇到已经计入掩码的字符该如何处理?
▷