Faulty Keyboard
EasyPrompt
Your laptop keyboard is faulty, and whenever you type a character 'i' on it, it reverses the string that you have written. Typing other characters works as expected.
You are given a 0-indexed string s, and you type each character of s using your faulty keyboard.
Return the final string that will be present on your laptop screen.
Example 1:
Input: s = "string"
Output: "rtsng"
Explanation:
After typing first character, the text on the screen is "s".
After the second character, the text is "st".
After the third character, the text is "str".
Since the fourth character is an 'i', the text gets reversed and becomes "rts".
After the fifth character, the text is "rtsn".
After the sixth character, the text is "rtsng".
Therefore, we return "rtsng".Example 2:
Input: s = "poiinter"
Output: "ponter"
Explanation:
After the first character, the text on the screen is "p".
After the second character, the text is "po".
Since the third character you type is an 'i', the text gets reversed and becomes "op".
Since the fourth character you type is an 'i', the text gets reversed and becomes "po".
After the fifth character, the text is "pon".
After the sixth character, the text is "pont".
After the seventh character, the text is "ponte".
After the eighth character, the text is "ponter".
Therefore, we return "ponter".
Constraints:
1 <= s.length <= 100sconsists of lowercase English letters.s[0] != 'i'
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We maintain a string, and for each character in the input, we either append it or, if the character is 'i', we reverse the entire string built so far. Using a StringBuilder in Java is convenient for this, as it is mutable and has a built-in reverse() method.
Algorithm
- Initialize an empty
StringBuildercalledresult. - Iterate through each character
cof the input strings. - If
cis equal to 'i':- Reverse the current content of the
resultStringBuilderusing itsreverse()method.
- Reverse the current content of the
- If
cis not 'i':- Append
cto the end of theresultStringBuilder.
- Append
- After the loop finishes, convert the
resultStringBuilderto a string and return it.
Walkthrough
The brute-force simulation is the most straightforward way to solve the problem. We use a mutable string data structure, like Java's StringBuilder, to construct the output string step-by-step.
We iterate through the input string s from left to right. For each character, we check if it's the faulty key 'i'.
- If the character is not 'i', we perform a standard append operation to the end of our
StringBuilder. - If the character is 'i', it triggers a reversal of all the text typed so far. We achieve this by calling the
reverse()method on ourStringBuilder.
After processing all characters in s, the StringBuilder holds the final state of the text on the screen. We then convert it to a standard String and return it. While this method is easy to understand, its performance suffers because the reversal operation's cost increases as the string grows.
class Solution { public String faultyKeyboard(String s) { StringBuilder result = new StringBuilder(); for (char c : s.toCharArray()) { if (c == 'i') { result.reverse(); } else { result.append(c); } } return result.toString(); }}Complexity
Time
O(N^2), where N is the length of the input string `s`. In the worst-case scenario, each 'i' character can trigger a reversal of the `StringBuilder`. Reversing a `StringBuilder` of length `k` takes O(k) time. Since `k` can grow up to N, and we might have up to N/2 'i's, the total time complexity becomes quadratic.
Space
O(N), where N is the length of the input string `s`. This space is used by the `StringBuilder` to store the resulting string, which can have a length up to N.
Trade-offs
Pros
Very simple and easy to implement.
Directly follows the logic from the problem description.
Cons
The time complexity is quadratic, which can be slow for larger inputs (though acceptable for the given constraints).
Repeatedly reversing a growing string is an inefficient operation.
A more efficient approach avoids the costly O(N) reversal operation by using a Deque (Double-Ended Queue). A Deque allows for constant-time additions at both the front and the back. We can simulate the string reversal by simply changing the end at which we add new characters. A boolean flag tracks whether the string is currently 'reversed'. When a non-'i' character is typed, we add it to the back of the deque if the state is normal, and to the front if the state is 'reversed'. An 'i' simply flips the state flag. This makes each step an O(1) operation.
Algorithm
- Initialize an empty
Deque<Character>(e.g.,ArrayDeque) and a boolean flagisReversedtofalse. - Iterate through each character
cof the input strings. - If
cis 'i':- Flip the
isReversedflag:isReversed = !isReversed.
- Flip the
- If
cis not 'i':- If
isReversedisfalse, add the character to the back of the deque:deque.addLast(c). - If
isReversedistrue, add the character to the front of the deque:deque.addFirst(c).
- If
- After the loop, create a
StringBuilderto build the final string. - If
isReversedisfalse, poll characters from the front of the deque (pollFirst) and append them to theStringBuilder. - If
isReversedistrue, poll characters from the back of the deque (pollLast) and append them to theStringBuilder. - Return the resulting string.
Walkthrough
This optimized approach recognizes that physically reversing the string repeatedly is inefficient. The core idea is that appending a character to a reversed string is equivalent to prepending the character to the original string. This behavior can be efficiently modeled using a Deque.
We maintain a Deque<Character> and a boolean flag, isReversed, initialized to false. We iterate through the input string s:
- When we see an 'i', we don't touch the deque. We simply flip the
isReversedflag. This O(1) operation acts as a 'virtual' reversal. - When we see any other character, we check the
isReversedflag. If it'sfalse, we are in the normal state, so we append the character to the end of the deque (addLast). IfisReversedistrue, we are in the reversed state, so we add the character to the front of the deque (addFirst). BothaddLastandaddFirstare O(1) operations.
After processing all characters, the deque contains the correct characters. To form the final string, we check the final state of isReversed. If it's false, we build the string by polling from the deque's front. If it's true, the sequence in the deque is effectively reversed, so we build the string by polling from the deque's back. This entire process has a linear time complexity.
import java.util.Deque;import java.util.ArrayDeque; class Solution { public String faultyKeyboard(String s) { Deque<Character> deque = new ArrayDeque<>(); boolean reversed = false; for (char c : s.toCharArray()) { if (c == 'i') { reversed = !reversed; } else { if (reversed) { deque.addFirst(c); } else { deque.addLast(c); } } } StringBuilder result = new StringBuilder(); if (reversed) { while (!deque.isEmpty()) { result.append(deque.removeLast()); } } else { while (!deque.isEmpty()) { result.append(deque.removeFirst()); } } return result.toString(); }}Complexity
Time
O(N), where N is the length of the input string `s`. We iterate through the string once. All operations inside the loop (adding to deque, flipping a boolean) and the final string construction are O(1) per character, leading to a total linear time complexity.
Space
O(N), where N is the length of the input string `s`. The `Deque` can store up to N characters.
Trade-offs
Pros
Optimal time complexity of O(N).
Efficiently handles the logic by avoiding actual string reversals.
Scales well even for larger inputs beyond the problem's constraints.
Cons
Slightly more complex to conceptualize than the brute-force approach.
Uses a more advanced data structure (
Deque) which might be less familiar to beginners.
Solutions
Solution
class Solution { public String finalString ( String s ) { StringBuilder t = new StringBuilder (); for ( char c : s . toCharArray ()) { if ( c == 'i' ) { t . reverse (); } else { t . append ( c ); } } return t . toString (); } }class Solution { public: string finalString ( string s ) { string t ; for ( char c : s ) { if ( c == 'i' ) { reverse ( t . begin (), t . end ()); } else { t . push_back ( c ); } } return t ; } };class Solution : def finalString ( self , s : str ) -> str : t = [] for c in s : if c == "i" : t = t [:: - 1 ] else : t . append ( c ) return "" . join ( t )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.