You are given two strings s and p where p is a subsequence of s. You are also given a distinct 0-indexed integer array removable containing a subset of indices of s (s is also 0-indexed).
You want to choose an integer k (0 <= k <= removable.length) such that, after removing k characters from s using the first k indices in removable, p is still a subsequence of s. More formally, you will mark the character at s[removable[i]] for each 0 <= i < k, then remove all marked characters and check if p is still a subsequence.
Return the maximum k you can choose such that p is still a subsequence of s after the removals.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
Example 1:
Input: s = "abcacb", p = "ab", removable = [3,1,0] Output: 2 Explanation: After removing the characters at indices 3 and 1, "abcacb" becomes "accb". "ab" is a subsequence of "accb". If we remove the characters at indices 3, 1, and 0, "abcacb" becomes "ccb", and "ab" is no longer a subsequence. Hence, the maximum k is 2.
Example 2:
Input: s = "abcbddddd", p = "abcd", removable = [3,2,1,4,5,6] Output: 1 Explanation: After removing the character at index 3, "abcbddddd" becomes "abcddddd". "abcd" is a subsequence of "abcddddd".
Example 3:
Input: s = "abcab", p = "abc", removable = [0,1,2,3,4] Output: 0 Explanation: If you remove the first index in the array removable, "abc" is no longer a subsequence.
Constraints:
1 <= p.length <= s.length <= 1050 <= removable.length < s.length0 <= removable[i] < s.lengthp is a subsequence of s.s and p both consist of lowercase English letters.removable are distinct.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy involves checking every possible combination to find the largest number of characters we can remove from a string while still ensuring another string remains a subsequence. It's like trying all possibilities, one at a time, to see which one works best. We systematically remove different sets of characters and then check if the target string is still hidden within the modified string.
Here's how the algorithm would work step-by-step:
def maximum_removable_characters_brute_force(string_one, string_two, removable_indices):
maximum_removals = 0
number_of_removable_indices = len(removable_indices)
for i in range(2 ** number_of_removable_indices):
indices_to_remove = []
for j in range(number_of_removable_indices):
if (i >> j) & 1:
indices_to_remove.append(removable_indices[j])
indices_to_remove.sort()
modified_string = list(string_one)
# Mark characters for removal by replacing them with an empty string
for index in indices_to_remove:
modified_string[index] = ''
modified_string = "".join(modified_string)
# Check if string_two is a subsequence of the modified string
string_two_index = 0
modified_string_index = 0
# If string_two is empty, any removals are a valid solution
if not string_two:
maximum_removals = max(maximum_removals, len(indices_to_remove))
continue
while string_two_index < len(string_two) and modified_string_index < len(modified_string):
if string_two[string_two_index] == modified_string[modified_string_index]:
string_two_index += 1
modified_string_index += 1
# Update maximum removals if string_two is still a subsequence
if string_two_index == len(string_two):
# If subsequence, track maximum removals
maximum_removals = max(maximum_removals, len(indices_to_remove))
return maximum_removalsWe want to find the most characters we can remove while still keeping a specific word as a subsequence of another. Instead of trying to remove every possible combination of characters, we'll use a smarter way of checking if a word is still a subsequence after removing some characters. This efficient approach avoids lots of unnecessary work.
Here's how the algorithm would work step-by-step:
def maximum_removable_characters(longer_word, shorter_word, removable_indices):
left = 0
right = len(removable_indices)
maximum_removable = 0
while left <= right:
middle = (left + right) // 2
# Check if we can remove this many characters
if is_subsequence_after_removal(longer_word, shorter_word, removable_indices[:middle]):
# If it's a subsequence, try removing more
maximum_removable = middle
left = middle + 1
else:
# If it's not, try removing fewer
right = middle - 1
return maximum_removable
def is_subsequence_after_removal(longer_word, shorter_word, indices_to_remove):
modified_longer_word = ""
indices_to_remove_set = set(indices_to_remove)
for index, char in enumerate(longer_word):
if index not in indices_to_remove_set:
modified_longer_word += char
short_pointer = 0
long_pointer = 0
# Check if shorter word is a subsequence
while short_pointer < len(shorter_word) and long_pointer < len(modified_longer_word):
if shorter_word[short_pointer] == modified_longer_word[long_pointer]:
short_pointer += 1
long_pointer += 1
# Return True if shorter word is a subsequence
# of the modified longer word
return short_pointer == len(shorter_word)| Case | How to Handle |
|---|---|
| Null or empty string s | Return 0 if s is null or empty, as no characters can be removed. |
| Null or empty string p | Return 0 if p is null or empty, as it vacuously satisfies being a subsequence. |
| Null or empty removable indices array | Return 0 if removable indices is null or empty, as no characters can be removed. |
| removable indices contains out-of-bounds indices | Filter out indices in removable that are out of bounds before processing. |
| removable indices contains duplicate indices | Handle duplicates by using a set to store unique removable indices; this avoids double removals. |
| p is not a subsequence of s even with no removals | Return 0 immediately since no removals will ever make p a subsequence. |
| s and p are identical strings | Return the length of the removable indices since all characters can be removed to make s an empty string (which trivially contains p). |
| Maximum length strings and removable indices to test for scalability | Ensure binary search and subsequence checking do not time out with maximum input size. |