字符替换与最长子串问题--滑动窗口

113 阅读3分钟

问题描述

小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