Maximize the Confusion of an Exam
MedPrompt
A teacher is writing a test with n true/false questions, with 'T' denoting true and 'F' denoting false. He wants to confuse the students by maximizing the number of consecutive questions with the same answer (multiple trues or multiple falses in a row).
You are given a string answerKey, where answerKey[i] is the original answer to the ith question. In addition, you are given an integer k, the maximum number of times you may perform the following operation:
- Change the answer key for any question to
'T'or'F'(i.e., setanswerKey[i]to'T'or'F').
Return the maximum number of consecutive 'T's or 'F's in the answer key after performing the operation at most k times.
Example 1:
Input: answerKey = "TTFF", k = 2
Output: 4
Explanation: We can replace both the 'F's with 'T's to make answerKey = "TTTT".
There are four consecutive 'T's.Example 2:
Input: answerKey = "TFFT", k = 1
Output: 3
Explanation: We can replace the first 'T' with an 'F' to make answerKey = "FFFT".
Alternatively, we can replace the second 'T' with an 'F' to make answerKey = "TFFF".
In both cases, there are three consecutive 'F's.Example 3:
Input: answerKey = "TTFTTFTT", k = 1
Output: 5
Explanation: We can replace the first 'F' to make answerKey = "TTTTTFTT"
Alternatively, we can replace the second 'F' to make answerKey = "TTFTTTTT".
In both cases, there are five consecutive 'T's.
Constraints:
n == answerKey.length1 <= n <= 5 * 104answerKey[i]is either'T'or'F'1 <= k <= n
Approaches
3 approaches with complexity analysis and trade-offs.
This approach involves checking every possible contiguous subarray within the answerKey. For each subarray, we count the number of 'T's and 'F's. If the count of either character is less than or equal to k, it means we can make the entire subarray uniform by performing at most k changes. We keep track of the maximum length of such a valid subarray.
Algorithm
- Initialize
maxLength = 0. - Use a nested loop structure. The outer loop with index
idetermines the start of a potential subarray, and the inner loop with indexjdetermines the end. - For each subarray
answerKey[i...j], count the number of 'T's (countT) and 'F's (countF). - A subarray can be made uniform if the number of characters to change is at most
k. This means eithercountT <= k(to make it all 'F's) orcountF <= k(to make it all 'T's). - If the condition
countT <= k || countF <= kis met, the current subarray of lengthj - i + 1is a valid candidate for the maximum length. - Update
maxLength = max(maxLength, j - i + 1). - After iterating through all possible subarrays, return
maxLength.
Walkthrough
We use two nested loops to define the start (i) and end (j) of each subarray. The outer loop iterates from the first character to the last to set the starting point. The inner loop expands the subarray from the starting point to the end of the string. Inside the inner loop, we maintain counts of 'T's and 'F's for the current subarray [i, j]. For each subarray, we check if it can be made entirely of 'T's (by changing at most k 'F's) or entirely of 'F's (by changing at most k 'T's). If this is possible, we update our maxLength with the current subarray's length (j - i + 1). After checking all O(N^2) subarrays, maxLength will hold the result.
class Solution { public int maxConsecutiveAnswers(String answerKey, int k) { int n = answerKey.length(); int maxLength = 0; if (k >= n / 2) { return n; } for (int i = 0; i < n; i++) { int countT = 0; int countF = 0; for (int j = i; j < n; j++) { if (answerKey.charAt(j) == 'T') { countT++; } else { countF++; } if (countT <= k || countF <= k) { maxLength = Math.max(maxLength, j - i + 1); } } } return maxLength; }}Complexity
Time
O(N^2), where N is the length of `answerKey`. The nested loops iterate through all O(N^2) subarrays.
Space
O(1), as we only use a few variables to store counts and pointers, regardless of the input size.
Trade-offs
Pros
Simple to understand and implement.
Correct for small input sizes.
Cons
Highly inefficient due to its O(N^2) time complexity.
Will result in a 'Time Limit Exceeded' (TLE) error on platforms like LeetCode for the given constraints.
This approach reframes the problem from "what is the maximum length?" to "is it possible to achieve a length of L?". This "yes/no" question is easier to answer and has a monotonic property: if a length L is possible, any length less than L is also possible. This allows us to use binary search on the possible answer lengths, from 1 to n.
Algorithm
- The core idea is to binary search for the answer (the maximum length). The possible lengths range from
1ton. - Define a search space with
low = 1andhigh = n. - In each step of the binary search, pick a
midlength and check if it's possible to form a consecutive sequence of this length using a helper functionisPossible(mid). - The
isPossible(length)function uses a fixed-size sliding window of the givenlengthto check if any such window can be made uniform with at mostkchanges. This check is done for both 'T' and 'F'. - To check for 'T's, we slide a window of size
lengthand see if any window contains<= k'F's. This check can be done in O(N) time. - If
isPossible(mid)is true, it means a length ofmidis achievable. We store it as a potential answer (ans = mid) and try for a larger length by settinglow = mid + 1. - If
isPossible(mid)is false, the lengthmidis too large, so we search for a smaller length by settinghigh = mid - 1. - The loop continues until
low > high, and the finalansis returned.
Walkthrough
We perform a binary search on the answer, which is the length of the consecutive sequence. The search space is from 1 to n. For each mid value (a potential length) in our binary search, we need a function isPossible(length) to check if a consecutive sequence of this length can be formed with at most k changes. This function itself uses a fixed-size sliding window of size length. It slides this window across the answerKey and checks if any window can be made all 'T's (i.e., has k or fewer 'F's) or all 'F's (i.e., has k or fewer 'T's). The sliding window check for a fixed length is an O(N) operation. Since this check is inside a binary search, the total time complexity is O(N log N).
class Solution { public int maxConsecutiveAnswers(String answerKey, int k) { int n = answerKey.length(); int low = 1, high = n; int ans = 0; while (low <= high) { int mid = low + (high - low) / 2; if (isPossible(answerKey, k, mid)) { ans = mid; low = mid + 1; } else { high = mid - 1; } } return ans; } private boolean isPossible(String answerKey, int k, int len) { return check(answerKey, k, len, 'T') || check(answerKey, k, len, 'F'); } private boolean check(String answerKey, int k, int len, char targetChar) { int n = answerKey.length(); int changesNeeded = 0; for (int i = 0; i < len; i++) { if (answerKey.charAt(i) != targetChar) { changesNeeded++; } } if (changesNeeded <= k) return true; for (int i = len; i < n; i++) { if (answerKey.charAt(i) != targetChar) changesNeeded++; if (answerKey.charAt(i - len) != targetChar) changesNeeded--; if (changesNeeded <= k) return true; } return false; }}Complexity
Time
O(N log N). The binary search takes O(log N) steps. In each step, we call `isPossible`, which takes O(N) time to slide the window across the string.
Space
O(1), as the algorithm uses a constant amount of extra space.
Trade-offs
Pros
Significantly more efficient than brute force.
Guaranteed to pass within the time limits for the given constraints.
Cons
More complex to implement compared to the brute-force or the final sliding window approach.
Not the most optimal solution, as a linear time solution exists.
This is the most efficient approach. The problem can be simplified to finding the longest subarray that contains at most k of the "other" character. We can solve this for both 'T' and 'F' and take the maximum. For example, to find the maximum consecutive 'T's, we find the longest subarray with at most k 'F's. This is a classic sliding window problem that can be solved in linear time.
Algorithm
- The problem is broken into two subproblems: find the max consecutive 'T's, and find the max consecutive 'F's. The final answer is the maximum of the two.
- To solve a subproblem (e.g., for 'T's), we find the longest subarray with at most
k'F's. - This is done using a variable-sized sliding window with
leftandrightpointers. - Initialize
left = 0,maxLength = 0, and a counter for the character we want to change (e.g.,f_count = 0). - Iterate
rightfrom0ton-1, expanding the window. - If
answerKey[right]is an 'F', incrementf_count. - If
f_countexceedsk, the window is invalid. Shrink the window from the left by incrementingleftuntil the window is valid again. While shrinking, ifanswerKey[left]was an 'F', decrementf_count. - After each expansion of
right, the window[left, right]is valid. UpdatemaxLength = max(maxLength, right - left + 1). - Repeat this process for the other character ('F') and return the overall maximum length.
Walkthrough
We can solve this problem by running the sliding window algorithm twice: once to find the longest sequence of 'T's and once for 'F's. The final answer is the maximum of these two results. Let's describe the process for finding the longest sequence of 'T's. We use a variable-sized window, defined by left and right pointers. We expand the window by moving right. We keep a count of 'F's in the window. If this count exceeds k, we shrink the window from the left until the count is at most k again. At each step, we update our maximum length with the current valid window's size. This ensures we find the longest valid subarray in a single pass.
class Solution { public int maxConsecutiveAnswers(String answerKey, int k) { // Find the max length for making all 'T's int maxForT = findMaxForChar(answerKey, k, 'T'); // Find the max length for making all 'F's int maxForF = findMaxForChar(answerKey, k, 'F'); // The answer is the maximum of the two scenarios return Math.max(maxForT, maxForF); } private int findMaxForChar(String answerKey, int k, char targetChar) { int n = answerKey.length(); int left = 0; int maxLength = 0; int changes = 0; // Count of the character to be changed for (int right = 0; right < n; right++) { // If the current character is not our target, we need to change it if (answerKey.charAt(right) != targetChar) { changes++; } // If we have used more than k changes, the window is invalid. // Shrink the window from the left until it's valid again. while (changes > k) { if (answerKey.charAt(left) != targetChar) { changes--; } left++; } // The window [left, right] is now a valid window. // Update the max length found so far. maxLength = Math.max(maxLength, right - left + 1); } return maxLength; }}Complexity
Time
O(N), where N is the length of `answerKey`. Each pointer, `left` and `right`, traverses the array at most once. Since we run this process twice (once for 'T' and once for 'F'), the total complexity is O(N) + O(N) = O(N).
Space
O(1). We only use a few variables for pointers and counts.
Trade-offs
Pros
Most efficient solution with linear time complexity.
Elegant and relatively straightforward to implement once the sliding window concept is understood.
Cons
It might be slightly less intuitive at first glance than the brute-force approach.
Solutions
Solution
class Solution { public int maxConsecutiveAnswers ( String answerKey , int k ) { return Math . max ( get ( 'T' , k , answerKey ), get ( 'F' , k , answerKey )); } public int get ( char c , int k , String answerKey ) { int l = 0 , r = 0 ; while ( r < answerKey . length ()) { if ( answerKey . charAt ( r ++) == c ) { -- k ; } if ( k < 0 && answerKey . charAt ( l ++) == c ) { ++ k ; } } return r - l ; } }class Solution { public: int maxConsecutiveAnswers ( string answerKey , int k ) { return max ( get ( 'T' , k , answerKey ), get ( 'F' , k , answerKey )); } int get ( char c , int k , string & answerKey ) { int l = 0 , r = 0 ; while ( r < answerKey . size ()) { if ( answerKey [ r ++ ] == c ) -- k ; if ( k < 0 && answerKey [ l ++ ] == c ) ++ k ; } return r - l ; } };class Solution : def maxConsecutiveAnswers ( self , answerKey : str , k : int ) -> int : def get ( c , k ): l = r = - 1 while r < len ( answerKey ) - 1 : r += 1 if answerKey [ r ] == c : k -= 1 if k < 0 : l += 1 if answerKey [ l ] == c : k += 1 return r - l return max ( get ( 'T' , k ), get ( 'F' , k ))Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.