Append Characters to String to Make Subsequence
MedPrompt
You are given two strings s and t consisting of only lowercase English letters.
Return the minimum number of characters that need to be appended to the end of s so that t becomes a subsequence of s.
A subsequence is a string that can be derived from another string by deleting some or no characters without changing the order of the remaining characters.
Example 1:
Input: s = "coaching", t = "coding"
Output: 4
Explanation: Append the characters "ding" to the end of s so that s = "coachingding".
Now, t is a subsequence of s ("coachingding").
It can be shown that appending any 3 characters to the end of s will never make t a subsequence.Example 2:
Input: s = "abcde", t = "a"
Output: 0
Explanation: t is already a subsequence of s ("abcde").Example 3:
Input: s = "z", t = "abcde"
Output: 5
Explanation: Append the characters "abcde" to the end of s so that s = "zabcde".
Now, t is a subsequence of s ("zabcde").
It can be shown that appending any 4 characters to the end of s will never make t a subsequence.
Constraints:
1 <= s.length, t.length <= 105sandtconsist only of lowercase English letters.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach iterates through each character of the target string t and, for each character, searches for its first occurrence in the source string s starting from the position after the last match. This is repeated until a character from t cannot be found in the remaining part of s.
Algorithm
- Initialize
matched_count = 0to count the characters oftfound ins. - Initialize
s_idx = 0as the starting index for searching ins. - Iterate through each character
t_charoftfrom left to right (indexifrom 0 tot.length() - 1). - Inside the loop, search for
t_charinsstarting froms_idxusing a function likeString.indexOf(). - If
t_charis found at positionfound_pos: a. Incrementmatched_count. b. Updates_idxtofound_pos + 1for the next search. - If
t_charis not found, break the loop as the subsequence cannot be extended. - After the loop,
matched_countholds the length of the longest prefix oftthat is a subsequence ofs. - Return
t.length() - matched_count.
Walkthrough
The goal is to find the length of the longest prefix of t that is a subsequence of s. We can achieve this by iterating through t and for each character, finding its corresponding match in s.
We maintain a variable, s_idx, which keeps track of the starting index for our search in s. This ensures that we find characters in the correct order. Initially, s_idx is 0.
We loop through t from left to right. In each iteration, we use a string searching function (like Java's s.indexOf(char, fromIndex)) to find the current character of t in s, starting from s_idx.
- If the character is found at some
found_pos, we've extended our subsequence match. We then updates_idxtofound_pos + 1so the next search begins after the current match. - If the character is not found, it's impossible to extend the subsequence further, so we stop.
The total number of characters found this way gives the length of the longest prefix of t that is a subsequence of s. The final answer is the total length of t minus this matched length.
class Solution { public int appendCharacters(String s, String t) { int t_len = t.length(); int matched_count = 0; int s_idx = 0; // Start searching in s from this index for (int i = 0; i < t_len; i++) { char t_char = t.charAt(i); // Find the character in s starting from s_idx int found_pos = s.indexOf(t_char, s_idx); if (found_pos != -1) { // Found the character, update search index for the next character s_idx = found_pos + 1; matched_count++; } else { // Character not found, break the loop break; } } return t_len - matched_count; }}Complexity
Time
O(N * M), where N is the length of `s` and M is the length of `t`. In the worst case, for each of the M characters in `t`, we might scan a large portion of `s`. Given the constraints, this would be too slow.
Space
O(1), as we only use a few variables to store indices and counts.
Trade-offs
Pros
Simple to understand and implement, especially using built-in string functions.
Cons
Inefficient due to repeated scanning of the string
s. TheindexOfmethod may rescan parts ofsin each iteration of the outer loop.
This is the most efficient approach. It uses two pointers, one for string s and one for string t, to find the longest prefix of t that is a subsequence of s in a single pass.
Algorithm
- Initialize two pointers,
i = 0for stringsandj = 0for stringt. - Use a
whileloop that continues as long asiis within the bounds ofsandjis within the bounds oft. - Inside the loop, compare
s.charAt(i)andt.charAt(j). - If they are equal, it's a match. Increment
jto look for the next character int. - Always increment
iin each iteration to scan throughs. - The loop terminates when either
sis fully scanned (i == s.length()) ortis fully matched (j == t.length()). - The value of
jat the end of the loop is the length of the longest prefix oftthat is a subsequence ofs. - The result is the number of characters in
tthat were not matched, which ist.length() - j.
Walkthrough
The core idea is to greedily match characters of t in s. We iterate through both strings simultaneously using two pointers.
We use a pointer i for s and a pointer j for t, both starting at index 0.
We traverse s with pointer i from left to right. At each character s.charAt(i), we check if it matches the character we are currently looking for from t, which is t.charAt(j).
- If
s.charAt(i) == t.charAt(j), it means we have found thej-th character oftins. We then advance the pointerjto look for the next character oft. - Regardless of whether a match is found, we always advance the pointer
ito move to the next character ins.
This process continues until we either exhaust s (i.e., i reaches s.length()) or we have found all characters of t (i.e., j reaches t.length()).
After the loop finishes, the value of j represents the number of characters from the beginning of t that were successfully found in s in the correct order. This is the length of the longest prefix of t that is a subsequence of s.
The number of characters we need to append to s is the number of characters in t that were not found, which is t.length() - j.
class Solution { public int appendCharacters(String s, String t) { int i = 0; // pointer for s int j = 0; // pointer for t int n = s.length(); int m = t.length(); while (i < n && j < m) { if (s.charAt(i) == t.charAt(j)) { j++; // Match found, move to the next character in t } i++; // Always move to the next character in s } // j now holds the length of the longest prefix of t that is a subsequence of s. // The remaining characters of t must be appended. return m - j; }}Complexity
Time
O(N), where N is the length of `s`. The `while` loop iterates through `s` at most once, making the approach linear in the length of `s`. This is efficient enough to pass within the given constraints.
Space
O(1), as it only uses two integer pointers, requiring constant extra space.
Trade-offs
Pros
Highly efficient with a linear time complexity.
Optimal solution as we must scan string
sat least once.Simple and elegant implementation with constant space usage.
Cons
There are no significant cons for this approach as it is optimal.
Solutions
Solution
class Solution { public int appendCharacters ( String s , String t ) { int m = s . length (), n = t . length (); for ( int i = 0 , j = 0 ; j < n ; ++ j ) { while ( i < m && s . charAt ( i ) != t . charAt ( j )) { ++ i ; } if ( i ++ == m ) { return n - j ; } } return 0 ; } }class Solution { public: int appendCharacters ( string s , string t ) { int m = s . size (), n = t . size (); for ( int i = 0 , j = 0 ; j < n ; ++ j ) { while ( i < m && s [ i ] != t [ j ]) { ++ i ; } if ( i ++ == m ) { return n - j ; } } return 0 ; } };class Solution : def appendCharacters ( self , s : str , t : str ) -> int : i , m = 0 , len ( s ) for j , c in enumerate ( t ): while i < m and s [ i ] != c : i += 1 if i == m : return len ( t ) - j i += 1 return 0Video 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.