“字符替换与最长字串问题”题目要求
一、问题描述
有一个由大写字母组成的字符串长度为n,现在可以对字符串中的字符进行修改:
每次允许将某个位置的字符修改为任意字符,比如说将字符串ABC第1个字符A改为B,则字符串变成BBC;
这个操作最多可以执行k次,现在想知道修改之后,字符串中由最多两种字母组成的子串最大长度。
输入格式
每个样例有两行;
第一行是整数 n, k,n 表示字符串长度,k 表示可以修改的最多次数;(3≤n≤2000, 1≤k≤100)
第二行是长度为 n 的字符串;
输出格式
每个样例一行,输出修改之后,由最多两种字母组成的子串最大长度;
二、测试样例
样例1:
输入:
6 1 ABCBAD
输出:5
样例2:
输入:
5 1 AEABD
输出:4
数据范围 :
(3≤
n≤2000, 1≤k≤100)
三、题目解析
3.1代码思路
采用滑动窗口和双重循环来处理所有可能的字符组合。具体思路如下:
-
遍历字符组合:通过两层嵌套循环,生成所有可能的不同字符组合
(c1, c2),在每种组合下寻找符合条件的最长子串。 -
双指针滑动窗口:
使用左右指针 left 和 right 定义当前窗口的范围。当 right 指针向右扩展时,根据字符是否为 c1 或 c2 增加计数器 count1 或 count2,否则增加 changes,表示此字符需要修改。当 changes > k 时,收缩左指针 left,直到窗口内的修改次数不超过 k。
- 更新最大长度:在窗口合法的情况下,计算窗口长度
right - left + 1,并更新最大长度maxLength。
3.2详细代码
import java.util.LinkedList;
import java.util.Queue;
public class Main {
public static int[] solution(int n, int[] a) {
// 创建一个队列,并将所有歌曲ID放入队列中
Queue<Integer> queue = new LinkedList<>();
for (int song : a) {
queue.add(song);
}
// 创建一个数组来存储播放顺序
int[] result = new int[n];
int index = 0;
// 模拟播放过程
while (!queue.isEmpty()) {
// 取出并播放当前第一首歌
int currentSong = queue.poll();
result[index++] = currentSong;
// 如果队列中还有歌曲,将当前第一首歌移到队列末尾
if (!queue.isEmpty()) {
int nextSong = queue.poll();
queue.add(nextSong);
}
}
return result;
}
public static void main(String[] args) {
System.out.println(Arrays.equals(solution(5, new int[]{5, 3, 2, 1, 4}), new int[]{5, 2, 4, 1, 3}));
System.out.println(Arrays.equals(solution(4, new int[]{4, 1, 3, 2}), new int[]{4, 3, 1, 2}));
System.out.println(Arrays.equals(solution(6, new int[]{1, 2, 3, 4, 5, 6}), new int[]{1, 3, 5, 2, 6, 4}));
}
}
四、知识总结
本代码展示了滑动窗口算法和双指针技术在处理字符串优化问题上的应用。
- 问题概述:代码实现了在字符串中找到最大长度的子串,使子串中仅包含两种指定字符,并且其他字符的修改次数不超过
k。这是典型的“滑动窗口+双指针”问题,用于在动态窗口内满足特定条件的最大子串搜索。 - 滑动窗口与双指针:滑动窗口技术通过两个指针 (
left和right) 在字符串上定义当前窗口的范围。右指针不断扩展窗口,遇到需要修改的字符时增加修改计数器;当修改次数超过限制k时,左指针收缩窗口,直至窗口满足条件。 - 字符组合遍历:通过嵌套循环生成所有可能的两字符组合
(c1, c2),并为每种组合寻找符合条件的最长子串。这种方式确保了所有字符对的情况都被考虑。 - 计数器更新:
count1和count2记录窗口中两个指定字符的数量,changes记录非这两个字符的数量。当changes超出允许的k时,通过调整左指针逐步恢复窗口合法性。 - 时间复杂度:由于字符组合的遍历为常数级别(26*26),算法的整体时间复杂度接近
O(n),适合中等规模的数据。