3324. Find the Sequence of Strings Appeared on the Screen
Problem Description
Alice has a special keyboard with only two keys to type a target string:
- Key 1: Appends the character "a" to the current string
- Key 2: Changes the last character to its next letter in the alphabet (e.g., "a"→"b", "b"→"c", ..., "z"→"a")
Starting with an empty string, Alice wants to type the target
string using the minimum number of key presses. The task is to return all intermediate strings that appear on the screen during this process, in the order they appear.
For example, to type "abc":
- Start with empty string ""
- Press Key 1: "a" (first character done)
- Press Key 1: "aa"
- Press Key 2: "ab" (second character done)
- Press Key 1: "aba"
- Press Key 2: "abb"
- Press Key 2: "abc" (target reached)
The solution simulates this process by:
- For each character
c
in the target string - Starting from the previous string (or empty if first character)
- Appending "a" and then using Key 2 to cycle through letters until reaching the desired character
- Recording each intermediate string in the result list
The code iterates through each target character, builds up from 'a' to the required character by cycling through the alphabet, and appends each intermediate result to the answer list.
Intuition
The key insight is that we need to build the target string character by character, and for each new character, we have a fixed optimal strategy.
Since we can only append 'a' with Key 1 and then modify it with Key 2, the most efficient way to add any character is to:
- First append 'a' to our current string
- Then repeatedly press Key 2 to cycle through the alphabet until we reach the desired character
For example, to add 'd' to an existing string, we must:
- Append 'a' first (Key 1)
- Transform 'a' → 'b' → 'c' → 'd' (Key 2 three times)
This gives us exactly 4 intermediate strings when adding 'd'.
The crucial observation is that there's no shortcut - we can't skip letters or go backwards in the alphabet. Each character requires us to start from 'a' and increment our way up. This means for a character at position i
in the alphabet, we need i+1
intermediate strings (including the initial 'a').
Since we want the minimum key presses, we simply follow this greedy approach for each character in the target. The order is deterministic: for each target character, we generate all strings from appending 'a' up to reaching that character.
This naturally leads to a simulation approach where we process the target character by character, and for each character, we generate all the intermediate strings by cycling from 'a' to that character.
Solution Approach
The simulation approach implements the typing process step by step:
Algorithm Steps:
-
Initialize an empty result list
ans
to store all intermediate strings that appear on the screen. -
Process each character in the target string one by one:
- For each character
c
intarget
:- Get the current string
s
(empty string ifans
is empty, otherwise the last string inans
) - Generate all intermediate strings by cycling through the alphabet from 'a' to
c
- Get the current string
- For each character
-
Generate intermediate strings for each character:
- Start with the current string
s
- Iterate through lowercase letters from 'a' onwards using
ascii_lowercase
- For each letter
a
in this iteration:- Create new string
t = s + a
(append the letter to current string) - Add
t
to the result list - If
a
equals the target characterc
, stop iterating
- Create new string
- Start with the current string
Implementation Details:
class Solution:
def stringSequence(self, target: str) -> List[str]:
ans = []
for c in target:
s = ans[-1] if ans else "" # Get current string or empty
for a in ascii_lowercase: # Iterate 'a' to 'z'
t = s + a # Append current letter
ans.append(t) # Record intermediate string
if a == c: # Stop when target char reached
break
return ans
Example Walkthrough for target = "ab"
:
- Start with
ans = []
- Process 'a':
s = ""
, iterate 'a', create "a", append toans = ["a"]
, stop - Process 'b':
s = "a"
, iterate 'a' then 'b', create "aa" then "ab", append both,ans = ["a", "aa", "ab"]
The time complexity is O(n × 26)
where n
is the length of target (worst case when all characters are 'z'), and space complexity is O(m)
where m
is the total number of intermediate strings generated.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through the solution for target = "bac"
:
Initial state: ans = []
Processing 'b' (target[0]):
- Current string
s = ""
(since ans is empty) - We need to cycle from 'a' to 'b':
- Append 'a':
t = "" + "a" = "a"
, add to ans →ans = ["a"]
- Append 'b':
t = "" + "b" = "b"
, add to ans →ans = ["a", "b"]
- Since we reached 'b', stop
- Append 'a':
Processing 'a' (target[1]):
- Current string
s = "b"
(last string in ans) - We need to cycle from 'a' to 'a':
- Append 'a':
t = "b" + "a" = "ba"
, add to ans →ans = ["a", "b", "ba"]
- Since we reached 'a', stop
- Append 'a':
Processing 'c' (target[2]):
- Current string
s = "ba"
(last string in ans) - We need to cycle from 'a' to 'c':
- Append 'a':
t = "ba" + "a" = "baa"
, add to ans →ans = ["a", "b", "ba", "baa"]
- Append 'b':
t = "ba" + "b" = "bab"
, add to ans →ans = ["a", "b", "ba", "baa", "bab"]
- Append 'c':
t = "ba" + "c" = "bac"
, add to ans →ans = ["a", "b", "ba", "baa", "bab", "bac"]
- Since we reached 'c', stop
- Append 'a':
Final result: ["a", "b", "ba", "baa", "bab", "bac"]
This demonstrates how each character requires starting from 'a' and incrementing through the alphabet until reaching the target character, with all intermediate strings being recorded.
Solution Implementation
1class Solution:
2 def stringSequence(self, target: str) -> List[str]:
3 """
4 Generate a sequence of strings by building up to the target string.
5 For each character in target, append characters from 'a' onwards until
6 reaching the target character.
7
8 Args:
9 target: The target string to build up to
10
11 Returns:
12 List of intermediate strings showing the build-up process
13 """
14 from string import ascii_lowercase
15 from typing import List
16
17 result = []
18
19 # Process each character in the target string
20 for target_char in target:
21 # Get the current base string (empty if result is empty)
22 current_base = result[-1] if result else ""
23
24 # Try each letter from 'a' until we reach the target character
25 for letter in ascii_lowercase:
26 # Create new string by appending current letter to base
27 new_string = current_base + letter
28 result.append(new_string)
29
30 # Stop when we've added the target character
31 if letter == target_char:
32 break
33
34 return result
35
1class Solution {
2 /**
3 * Generates a sequence of strings by incrementally building up to the target string.
4 * For each character in the target, it creates intermediate strings by appending
5 * characters from 'a' up to the target character.
6 *
7 * @param target The target string to build up to
8 * @return A list containing all intermediate strings in the sequence
9 */
10 public List<String> stringSequence(String target) {
11 // Initialize result list to store the sequence of strings
12 List<String> result = new ArrayList<>();
13
14 // Process each character in the target string
15 for (char targetChar : target.toCharArray()) {
16 // Get the base string (empty if result is empty, otherwise the last string in result)
17 String baseString = result.isEmpty() ? "" : result.get(result.size() - 1);
18
19 // Generate all intermediate strings by appending characters from 'a' to targetChar
20 for (char currentChar = 'a'; currentChar <= targetChar; ++currentChar) {
21 // Create new string by appending current character to base string
22 String newString = baseString + currentChar;
23 // Add the new string to the result list
24 result.add(newString);
25 }
26 }
27
28 return result;
29 }
30}
31
1class Solution {
2public:
3 vector<string> stringSequence(string target) {
4 vector<string> result;
5
6 // Process each character in the target string
7 for (char targetChar : target) {
8 // Get the current base string (empty if result is empty, otherwise the last string in result)
9 string currentBase = result.empty() ? "" : result.back();
10
11 // Generate all strings from 'a' to targetChar by appending to the base
12 for (char currentChar = 'a'; currentChar <= targetChar; ++currentChar) {
13 // Create new string by appending current character to the base
14 string newString = currentBase + currentChar;
15 // Add the new string to the result sequence
16 result.push_back(newString);
17 }
18 }
19
20 return result;
21 }
22};
23
1/**
2 * Generates a sequence of strings by progressively building towards a target string.
3 * For each character in the target, it creates intermediate strings by appending
4 * characters from 'a' up to the target character.
5 *
6 * @param target - The target string to build towards
7 * @returns An array of strings showing the progression
8 */
9function stringSequence(target: string): string[] {
10 // Array to store the sequence of strings
11 const result: string[] = [];
12
13 // Process each character in the target string
14 for (const targetChar of target) {
15 // Get the previous string as base, or empty string if no previous exists
16 const previousString: string = result.length > 0 ? result[result.length - 1] : '';
17
18 // Build strings by appending characters from 'a' to the current target character
19 for (let charCode = 'a'.charCodeAt(0); charCode <= targetChar.charCodeAt(0); charCode++) {
20 // Create new string by appending the current character to the base
21 const currentString: string = previousString + String.fromCharCode(charCode);
22 // Add the newly formed string to the result
23 result.push(currentString);
24 }
25 }
26
27 return result;
28}
29
Time and Space Complexity
Time Complexity: O(n² × |Σ|)
, where n
is the length of the target string and |Σ|
is the size of the character set (26 for lowercase letters).
- The outer loop iterates through each character in the target string:
O(n)
- For each character position, the inner loop iterates through the lowercase letters from 'a' until it reaches the target character
- In the worst case, this requires iterating through all 26 letters:
O(|Σ|)
- Inside the inner loop, we perform string concatenation
s + a
, wheres
can have length up ton-1
- String concatenation takes
O(n)
time since strings are immutable in Python - Therefore, the total time complexity is
O(n) × O(|Σ|) × O(n) = O(n² × |Σ|)
Space Complexity: O(n² × |Σ|)
- The
ans
list stores all intermediate strings generated during the process - For the first character, we generate at most
|Σ|
strings of length 1 - For the second character, we generate at most
|Σ|
strings of length 2 - For the
i
-th character, we generate at most|Σ|
strings of lengthi
- Total number of strings: at most
n × |Σ|
- Total space for all strings:
Σ(i=1 to n) i × |Σ| = |Σ| × n × (n+1) / 2 = O(n² × |Σ|)
- Additionally, each string operation creates temporary strings, but these don't affect the asymptotic complexity
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrectly handling the string building process
A common mistake is misunderstanding how the keyboard works. Some might think Key 2 modifies the entire last string rather than just the last character:
Incorrect approach:
# Wrong: Trying to modify the entire last string
result = []
for target_char in target:
if not result:
result.append("a")
else:
# This doesn't follow the key mechanics correctly
result.append(result[-1] + "a")
# Then trying to change the last character
while result[-1][-1] != target_char:
last = result[-1]
next_char = chr((ord(last[-1]) - ord('a') + 1) % 26 + ord('a'))
result.append(last[:-1] + next_char)
Correct approach:
# Each intermediate state must be recorded result = [] for target_char in target: base = result[-1] if result else "" # Must append 'a' first, then cycle through alphabet for letter in ascii_lowercase: result.append(base + letter) if letter == target_char: break
2. Not recording all intermediate states
Another pitfall is only recording the final state for each character, missing the intermediate transformations:
Incorrect approach:
# Wrong: Only recording final states result = [] current = "" for target_char in target: current = current + target_char result.append(current) return result # Missing all the intermediate 'a', 'b', 'c'... transformations
Correct approach:
# Must record every single key press result result = [] for target_char in target: base = result[-1] if result else "" # Record each transformation from 'a' to target_char for letter in ascii_lowercase: result.append(base + letter) if letter == target_char: break
3. Handling wrap-around incorrectly
While the problem states Key 2 changes 'z' to 'a', the solution doesn't need explicit wrap-around handling since we always start from 'a' for each new character. However, misunderstanding this could lead to unnecessary complexity:
Overcomplicated approach:
# Unnecessary: Handling wrap-around when not needed
for target_char in target:
base = result[-1] if result else ""
current_char = 'a'
while True:
result.append(base + current_char)
if current_char == target_char:
break
# Unnecessary wrap-around logic
current_char = chr((ord(current_char) - ord('a') + 1) % 26 + ord('a'))
Simpler correct approach:
# Just iterate through ascii_lowercase and break when found for letter in ascii_lowercase: result.append(base + letter) if letter == target_char: break
Which algorithm should you use to find a node that is close to the root of the tree?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!