问题背景
有一个由大写字母组成的字符串长度为n,现在可以对字符串中的字符进行修改:每次允许将某个位置的字符修改为任意字符,比如说将字符串ABC第1个字符A改为B,则字符串变成BBC;这个操作最多可以执行k次,现在想知道修改之后,字符串中由最多两种字母组成的子串最大长度。
代码分析
solution 方法
这个方法的核心是使用滑动窗口的技术,遍历所有可能的字母对,找到最多修改 k 次后,能得到的最长由两种字母组成的子串。
java
复制代码
public static int solution(int n, int k, String inp) {
int maxLen = 0;
// 尝试每一对字符作为子串的字符
for (char c1 = 'A'; c1 <= 'Z'; c1++) {
for (char c2 = 'A'; c2 <= 'Z'; c2++) {
if (c1 == c2) continue; // 同一字符对跳过
int left = 0, right = 0;
int count1 = 0, count2 = 0;
int modifications = 0;
while (right < n) {
// 处理右指针移动,更新计数
if (inp.charAt(right) == c1) count1++;
else if (inp.charAt(right) == c2) count2++;
else modifications++; // 若当前字符既不是 c1 也不是 c2,需要修改
// 若修改次数超过 k,收缩窗口
while (modifications > k) {
if (inp.charAt(left) == c1) count1--;
else if (inp.charAt(left) == c2) count2--;
else modifications--;
left++; // 缩小窗口,从左侧移出
}
// 更新最大长度
maxLen = Math.max(maxLen, right - left + 1);
right++; // 向右扩展窗口
}
}
}
return maxLen;
}
主要思路
-
遍历所有字符对:首先,尝试所有可能的字符对
(c1, c2),其中c1和c2是子串中可能的两种字符。从字符A到Z逐一尝试每一对字符。如果两个字符相同,直接跳过。 -
滑动窗口:对每一对字符
(c1, c2),使用滑动窗口来寻找符合条件的最大子串。窗口通过两个指针left和right来表示,right逐渐向右扩展,left向右收缩。- 更新窗口:如果当前窗口中的字符是
c1或c2,就分别增加count1或count2。如果字符既不是c1也不是c2,则需要计入修改次数modifications。 - 收缩窗口:当
modifications超过k时,我们通过移动左指针left来收缩窗口,直到modifications不再超过k。此时,窗口内的字符全部可以通过不超过k次修改变成c1或c2。 - 更新最大长度:每次右指针移动时,更新最大子串长度
maxLen。
- 更新窗口:如果当前窗口中的字符是
-
返回结果:最终返回通过最多
k次修改得到的最大长度。