问题描述
小R得到了一个由大写字母组成的字符串,长度为 n。她可以对字符串中的字符进行修改,每次操作允许将某个位置的字符修改为任意字符。例如,字符串 ABC 的第一个字符 A 改为 B,则字符串变为 BBC。她最多可以进行 k 次这样的修改。
小R想知道,通过最多 k 次修改后,字符串中由最多两种不同字母组成的最长连续子串的长度是多少。
测试样例
样例1:
输入:
n = 6 ,k = 1 ,inp = "ABCBAD"
输出:5
样例2:
输入:
n = 5 ,k = 1 ,inp = "AEABD"
输出:4
样例3:
输入:
n = 8 ,k = 2 ,inp = "AAAABBCD"
输出:8
问题解读
遇到最长连续子串的长度问题,首先就应该首先想到滑动窗口或者动态规划, 这里由于区间内修改的字母不确定,状态转移方程不好确定,所以选择遍历所有符合条件的窗口的滑动窗口算法
滑动窗口模板
基本模板为:确定窗口左边界为0, 右边界为0, 遍历右边界, 如果不满足条件(区间内有两种以上不同字母),就缩短左边界直至满足条件
//初始化左边界
int l = 0;
//遍历右边界
for(int r = 0; r<n; r++)
{
//窗口不符合条件
while(!condition)
{
//调整区间值.....
....
//缩短左边界
l++;
}
//窗口符合条件, 长度进行记录
res = max(res, r-l+1);
}
本题解法
回到这道题中, 条件为通过最多 k 次修改后,字符串中由最多两种不同字母, 可以构建哈希表记录每个字母的词频,进行降序排序,词频前两高的字母留下,其他字母进行修改,这样可以得到最小的修改次数为:窗口长度-词频前两高字母的出现次数, 如果最小修改次数>k, 说明不符合,需要对区间进行修改
需要注意的点
- 每次修改区间,词频都会发生变化, 所以需要有一个临时数组记录实时变化排序后的词频
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int solution(int n, int k, std::string s) {
// Edit your code here
int l = 0;
//构建数组存放26个字母的词频
vector<int> count(26);
int res = 0;
for(int r=0; r<n; r++)
{
//转为索引值
int i = s[r]-'A';
//词频加一
count[i]++;
//拷贝构造用于找寻词频前两大的数
vector<int> sort_count = count;
sort(sort_count.begin(), sort_count.end(), greater<int>());
//如果需要修改的值大于k, 不符合条件
while(sort_count[0]+sort_count[1]+k<r-l+1)
{
//词频减一
count[s[l]-'A']--;
//缩短左边界
l++;
//重新计算词频大小
vector<int> sort_count = count;
sort(sort_count.begin(), sort_count.end(), less<int>());
}
res = max(res, r-l+1);
}
return res;
}
python提交版代码
def solution(n, k, s):
l = 0
count = [0] * 26
res = 0
for r in range(n):
i = ord(s[r]) - ord('A') # 获取当前字符的索引
count[i] += 1
# 对 count 列表进行排序,并获取前两个最大值
sort_count = sorted(count, reverse=True)
# 当最大两个字符的频率加上 k 小于当前窗口大小时,缩小窗口
while sort_count[0] + sort_count[1] + k < r - l + 1:
count[ord(s[l]) - ord('A')] -= 1
l += 1
sort_count = sorted(count, reverse=True) # 重新排序
# 更新结果
res = max(res, r - l + 1)
return res