“字符替换与最长字串问题”题目要求
一、问题描述
有一个由大写字母组成的字符串长度为n,现在可以对字符串中的字符进行修改:
每次允许将某个位置的字符修改为任意字符,比如说将字符串ABC第1个字符A改为B,则字符串变成BBC;
这个操作最多可以执行k次,现在想知道修改之后,字符串中由最多两种字母组成的子串最大长度。
例如,给定歌单 [5, 3, 2, 1, 4],真实的播放顺序是 [5, 2, 4, 1, 3]。
保证歌曲中的id两两不同。
输入格式
每个样例有两行;
第一行是整数 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)
输出:4
三、题目解析
3.1代码思路
- 初始化队列:使用
LinkedList实现Queue接口,并将所有歌曲ID放入队列中。 - 模拟播放过程:使用
poll()方法从队列中取出并播放当前第一首歌。如果队列中还有歌曲,使用poll()方法取出当前第一首歌,并使用add()方法将其移到队列末尾。 - 记录播放顺序:将每次播放的歌曲ID记录到
result数组中。
13. 定义 applyOperation 方法
public static int solution(int n, int k, String inp) {
int maxLength = 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; // 记录c1和c2的出现次数
int changes = 0; // 记录当前窗口内的修改次数
while (right < n) {
// 更新当前字符的计数
if (inp.charAt(right) == c1) count1++;
else if (inp.charAt(right) == c2) count2++;
else changes++; // 如果不是c1或c2,则需要修改
// 如果修改次数超过k,移动左指针直到修改次数不超过k
while (changes > k) {
// 更新左指针字符的计数
if (inp.charAt(left) == c1) count1--;
else if (inp.charAt(left) == c2) count2--;
else changes--; // 如果不是c1或c2,则修改次数减少
left++;
}
// 更新最大长度
maxLength = Math.max(maxLength, right - left + 1);
right++;
}
}
}
return maxLength;
}
public static void main(String[] args) {
System.out.println(solution(6, 1, "ABCBAD") == 5);
System.out.println(solution(5, 1, "AEABD") == 4);
}
}
四、知识总结
这段代码通过结合队列操作与循环模拟的方式,较好地实现了自定义的播放机制,并利用队列数据结构的特点简化了复杂的逻辑。使用 Queue 数据结构来模拟播放列表,按照 FIFO 规则取出当前歌曲,实现顺序播放。利用队列的特性来处理“当前歌曲播放后,下一个歌曲移到末尾”的需求,这种操作非常适合队列。 使用 while 循环,通过 poll() 方法不断从队列中取出元素,直到队列为空。循环中的每一步都模拟了一个播放过程。这种模拟方式便于对流程进行控制,使得代码能按需改变播放顺序,例如将“跳过”的歌曲重新添加到队列末尾。用一个 result 数组来保存每首歌曲的播放顺序,确保了最终输出格式符合要求。每轮循环都通过 poll() 移除队首元素并条件性地重新插入元素,实现队列中元素的状态更新。这种状态更新思想适合处理类似调度、轮换等需求。