问题描述
小C拥有两个长度为 n 的字符串 s 和 t。字符串 s 中最多有 10 个不同的字符。她希望找到一些区间 [l, r],在这些区间中,对于任意的 i ∈ [l, r],总满足 s_i = t_i,称这样的区间为匹配区间。
小C还可以对字符串 s 进行一些修改:她可以选择字符串 s 中的一个字符 s_i,将其放入集合 S,并将 s_i 修改为任意字符。集合 S 中的不同字符数量不能超过 k。
她想知道,在最多修改 k 个不同字符的情况下,能够获得的最大匹配区间数量是多少。
测试样例
样例1:
输入:
n = 3 , k = 1 , s = "abc" , t = "azc"
输出:5
样例2:
输入:
n = 5 , k = 2 , s = "apple" , t = "ample"
输出:44
样例3:
输入:
n = 6 , k = 2 , s = "banana" , t = "bandna"
输出:45
问题理解
- 匹配区间:我们需要找到一些区间
[l, r],在这些区间中,对于任意的i ∈ [l, r],总满足s_i = t_i。 - 修改操作:我们可以对字符串
s进行一些修改,选择字符串s中的一个字符s_i,将其放入集合S,并将s_i修改为任意字符。集合S中的不同字符数量不能超过k。 - 目标:在最多修改
k个不同字符的情况下,找到能够获得的最大匹配区间数量。
数据结构选择
- 滑动窗口:我们可以使用滑动窗口来动态地维护当前窗口内的字符匹配情况。
- 哈希表:使用哈希表来记录当前窗口内需要修改的字符及其数量。
算法步骤
-
初始化:
- 使用两个指针
left和right来表示当前窗口的左右边界。 - 使用一个哈希表
charCount来记录当前窗口内需要修改的字符及其数量。
- 使用两个指针
-
扩展窗口:
- 移动
right指针,扩展窗口。 - 如果
s[right] != t[right],则将s[right]加入charCount。
- 移动
-
缩小窗口:
- 如果
charCount中的不同字符数量超过k,则移动left指针,缩小窗口,直到charCount中的不同字符数量不超过k。
- 如果
-
计算匹配区间数量:
- 在每次扩展或缩小窗口后,计算当前窗口内的匹配区间数量,并更新最大匹配区间数量。
总结
通过滑动窗口和哈希表的结合,我们可以动态地维护当前窗口内的字符匹配情况,并在不超过 k 次修改的情况下,找到最大的匹配区间数量。
优化思路
-
减少哈希表操作:
- 当前代码在每次扩展和缩小窗口时都会频繁地操作哈希表,这可能会导致性能瓶颈。我们可以考虑减少哈希表的操作次数。
-
提前计算匹配字符:
- 在扩展窗口时,如果
s[right] == t[right],我们可以直接跳过这个字符,因为不需要修改它。
- 在扩展窗口时,如果
-
优化窗口缩小条件:
- 当前代码在每次扩展窗口后都会检查
charCount的大小是否超过k,这可能会导致不必要的缩小操作。我们可以考虑在扩展窗口时提前判断是否需要缩小窗口。
- 当前代码在每次扩展窗口后都会检查
public static int solution(int n, int k, String s, String t) {
int left = 0, right = 0;
int maxMatchCount = 0;
Map<Character, Integer> charCount = new HashMap<>();
while (right < n) {
// 扩展窗口,更新 charCount
char rightChar = s.charAt(right);
if (s.charAt(right) != t.charAt(right)) {
charCount.put(rightChar, charCount.getOrDefault(rightChar, 0) + 1);
}
right++;
// 如果 charCount 中的不同字符数量超过 k,则缩小窗口
while (charCount.size() > k) {
char leftChar = s.charAt(left);
if (s.charAt(left) != t.charAt(left)) {
charCount.put(leftChar, charCount.get(leftChar) - 1);
if (charCount.get(leftChar) == 0) {
charCount.remove(leftChar);
}
}
left++;
}
// 计算当前窗口内的匹配区间数量
int currentMatchCount = right - left;
maxMatchCount = Math.max(maxMatchCount, currentMatchCount);
}
return maxMatchCount;
}