424. 替换后的最长重复字符(从暴力到滑动)
给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。
在执行上述操作后,返回 包含相同字母的最长子字符串的长度。
示例 1:
输入:s = "ABAB", k = 2
输出:4
解释:用两个'A'替换为两个'B',反之亦然。
示例 2:
输入:s = "AABABBA", k = 1
输出:4
解释:
将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。
子串 "BBBB" 有最长重复字母, 答案为 4。
可能存在其他的方法来得到同样的结果。
提示:
1 <= s.length <= 105
s 仅由大写英文字母组成
0 <= k <= s.length
证明1:如果长度为 L 的子串不符合题目的要求,那么左边界固定,长度更长的子串也不符合题目的要求。
答:记 count(X) 表示长度为 L 的子串中,字符 X 出现的次数。
不失一般性,假设长度为 L 的子串,出现最多的字符为 A,记 count(A)=x。其余字符均为 B,记 count(B)=y。由字符 A 出现次数最多,可知 x≥y。又由于长度为 L 的子串不符合题目的要求,可知 y>k。起点固定的情况下,考虑更长的子串:
如果接下来看到的字符都是 A(频数最多的字符越来越多),依然须要考虑把之前看到的 B 全部替换成为 A,由于 count(B)=y>k,这是不能做到的;
如果接下来看到的字符不是 A(频数较少的字符超过原来频数最多的字符),那么须要考虑把之前看到的 A 全部替换成为新的频数最多的字符,由于 count(A)=x≥y>k,这也是不能做到的。
说明:这里我们只讨论了滑动窗口扫过的子区间只含有 2 种字符的情况,如果滑动窗口扫过的子区间只含有 3 种以及 3 种以上字符,讨论是类似的。
显然有暴力,穷举左右端点
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
check(i,j);
}
}
用证明1优化,内层循环j遇到不合法的字符串时 $[left,right']$ right' > 最后一个合法j 也不合法 ,可以直接跳过
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(!check(i,j)) break;
}
}
退出内层循环后我们移动i到下一位置,但j不用回到i+1,因为更大大字串最少也是上轮j+1的位置
int j=0;
for(int i=0;i<n;i++){
while(++j&&j<n){
if(!check(i,j)) break
}
}
具体实现
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int characterReplacement(string s, int k) {
int maxLength = 0; // 用于存储最长子串的长度
int count[26] = {0}; // 用于存储每个字符的出现次数
int maxCount = 0; // 窗口内出现次数最多的字符的出现次数
int n = s.length();
// 对左指针穷举,j=-1 确保初始位置0的字符进入统计数组
for (int i = 0, j = -1; j < n; i++) {
// 使用 while 循环扩展右指针
while (++j < n) {
// 更新当前字符的计数
count[s[j] - 'A']++;
// 更新窗口内出现次数最多的字符的计数
maxCount = max(maxCount, count[s[j] - 'A']);
// 检查当前窗口是否满足条件
if ((j - i + 1) - maxCount > k) {
// 如果不满足条件,跳出 while 循环
count[s[i] - 'A']--; // 左指针字符计数减少
break;
}
// 更新最长子串的长度
maxLength = max(maxLength, j - i + 1);
}
}
return maxLength;
}
};
int main() {
Solution solution;
string s = "AABABBA";
int k = 1;
int result = solution.characterReplacement(s, k);
cout << "最长子串的长度: " << result << endl; // 输出应为 4
// 更多测试用例
vector<pair<string, int>> testCases = {
{"AABABBA", 1},
{"ABAB", 2},
{"AABBBCC", 2},
{"AAAA", 0},
{"A", 1},
{"AAABBB", 3},
{"BAAAB", 3},
{"KRSCDCSONAM", 4}
};
for (const auto& testCase : testCases) {
string input = testCase.first;
int kVal = testCase.second;
result = solution.characterReplacement(input, kVal);
cout << "字符串: \"" << input << "\", k = " << kVal
<< " => 最长子串的长度: " << result << endl;
}
return 0;
}


浙公网安备 33010602011771号