【每日一题】LeetCode 2024.考试的最大困扰度(字符串、二分查找、前缀和、滑动窗口)
题目描述
一位老师正在出一场由 n
道判断题构成的考试,每道题的答案为 true (用 'T'
表示)或者 false (用 'F'
表示)。老师想增加学生对自己做出答案的不确定性,方法是 最大化 有 连续相同 结果的题数。(也就是连续出现 true 或者连续出现 false)。
给定一个由 ‘T’ 和 ‘F’ 组成的字符串 answerKey
,表示一系列判断题的答案。我们的目标是通过最多 k
次操作,使得字符串中连续的相同字符(‘T’ 或 ‘F’)的最大数量最大化。每次操作可以改变一个字符的值。
思路分析
这个问题可以通过动态规划、贪心算法、滑动窗口来解决。这里我们采用滑动窗口算法的思路:
-
贪心策略:我们希望最大化连续相同字符的数量,因此我们可以考虑两种情况:将所有的 ‘F’ 转换为 ‘T’ 或者将所有的 ‘T’ 转换为 ‘F’。这样,我们只需要考虑两种情况中的最优解。
-
滑动窗口:使用滑动窗口来维护当前窗口内连续相同字符的数量。窗口的左边界和右边界分别表示窗口的起始和结束位置。
滑动窗口算法分析
- 初始化:定义两个指针
i
和j
分别代表窗口的右边界和左边界,以及一个计数器cnt
来记录窗口内与目标字符不同的字符数量。 - 遍历字符串:通过遍历字符串,将每个字符与目标字符(‘T’ 或 ‘F’)进行比较。
- 更新窗口:如果当前字符与目标字符相同,则增加
cnt
。如果不同,则尝试通过移动窗口的左边界(即增加j
)来减少cnt
,直到窗口内的不同字符数量不超过k
。 - 计算最大长度:在每次移动窗口的过程中,更新并记录当前窗口的最大长度,这个长度就是当前条件下能够达到的最大连续相同字符的数量。
- 返回结果:最后,返回在两种情况下(将 ‘F’ 转换为 ‘T’ 和将 ‘T’ 转换为 ‘F’)的最大连续数量中的较大者。
- 初始化:定义两个指针
输入示例
示例 1:
输入:answerKey = "TTFF", k = 2
输出:4
解释:我们可以将两个 'F' 都变为 'T' ,得到 answerKey = "TTTT" 。
总共有四个连续的 'T' 。
示例 2:
输入:answerKey = "TFFT", k = 1
输出:3
解释:我们可以将最前面的 'T' 换成 'F' ,得到 answerKey = "FFFT" 。
或者,我们可以将第二个 'T' 换成 'F' ,得到 answerKey = "TFFF" 。
两种情况下,都有三个连续的 'F' 。
示例 3:
输入:answerKey = "TTFTTFTT", k = 1
输出:5
解释:我们可以将第一个 'F' 换成 'T' ,得到 answerKey = "TTTTTFTT" 。
或者我们可以将第二个 'F' 换成 'T' ,得到 answerKey = "TTFTTTTT" 。
两种情况下,都有五个连续的 'T' 。
代码实现
class Solution {
public int maxConsecutiveAnswers(String answerKey, int k) {
// 将字符串转换为字符数组
char[] chars = answerKey.toCharArray();
// 分别计算将所有 'F' 转换为 'T' 和将所有 'T' 转换为 'F' 的最大连续数量
return Math.max(getCnt(chars, 'T', k), getCnt(chars, 'F', k));
}
// 计算将指定字符转换为 c 的最大连续数量
private int getCnt(char[] chars, char c, int k) {
int ans = 0; // 用于存储最大连续数量
for (int i = 0, j = 0, cnt = 0; i < chars.length; i++) {
// 如果当前字符与目标字符相同,增加计数
if (chars[i] == c) {
cnt++;
}
// 当连续相同字符的数量超过 k 时,移动窗口左边界
while (cnt > k) {
if (chars[j] == c) {
cnt--;
}
j++;
}
// 更新最大连续数量
ans = Math.max(ans, i - j + 1);
}
return ans;
}
}